Coverage Report

Created: 2026-09-28 07:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/rust/src/http2/http2.rs
Line
Count
Source
1
/* Copyright (C) 2020-2022 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::decompression;
19
use super::detect;
20
use super::parser;
21
use super::range;
22
23
use crate::applayer::{self, *};
24
use crate::conf::{conf_get, get_memval};
25
use crate::core::*;
26
use crate::direction::Direction;
27
use crate::dns::dns::DnsVariant;
28
use crate::filecontainer::*;
29
use crate::filetracker::*;
30
use crate::flow::Flow;
31
use crate::frames::Frame;
32
33
use crate::dns::dns::{dns_parse_request, dns_parse_response, DNSTransaction};
34
35
use nom7::Err;
36
use std;
37
use std::collections::VecDeque;
38
use std::ffi::CString;
39
use std::fmt;
40
use std::io;
41
use suricata_sys::sys::{
42
    AppLayerParserState, AppProto, SCAppLayerForceProtocolChange,
43
    SCAppLayerParserConfParserEnabled, SCAppLayerParserRegisterLogger,
44
    SCAppLayerProtoDetectConfProtoDetectionEnabled,
45
};
46
use suricata_sys::sys::AppProtoEnum::ALPROTO_HTTP1;
47
48
static mut ALPROTO_HTTP2: AppProto = ALPROTO_UNKNOWN;
49
static mut ALPROTO_DOH2: AppProto = ALPROTO_UNKNOWN;
50
51
const HTTP2_DEFAULT_MAX_FRAME_SIZE: u32 = 16384;
52
const HTTP2_MAX_HANDLED_FRAME_SIZE: usize = 65536;
53
const HTTP2_MIN_HANDLED_FRAME_SIZE: usize = 256;
54
55
pub static mut SURICATA_HTTP2_FILE_CONFIG: Option<&'static SuricataFileContext> = None;
56
57
#[no_mangle]
58
40
pub extern "C" fn SCHttp2Init(context: &'static mut SuricataFileContext) {
59
40
    unsafe {
60
40
        SURICATA_HTTP2_FILE_CONFIG = Some(context);
61
40
    }
62
40
}
63
64
#[repr(u8)]
65
#[derive(Copy, Clone, PartialOrd, PartialEq, Eq)]
66
pub enum HTTP2ConnectionState {
67
    Http2StateInit = 0,
68
    Http2StateMagicDone = 1,
69
}
70
71
const HTTP2_FRAME_HEADER_LEN: usize = 9;
72
const HTTP2_MAGIC_LEN: usize = 24;
73
const HTTP2_FRAME_GOAWAY_LEN: usize = 8;
74
const HTTP2_FRAME_RSTSTREAM_LEN: usize = 4;
75
const HTTP2_FRAME_PRIORITY_LEN: usize = 5;
76
const HTTP2_FRAME_WINDOWUPDATE_LEN: usize = 4;
77
pub static mut HTTP2_MAX_TABLESIZE: u32 = 65536; // 0x10000
78
                                                 // maximum size of reassembly for header + continuation
79
static mut HTTP2_MAX_REASS: usize = 102400;
80
static mut HTTP2_MAX_STREAMS: usize = 4096; // 0x1000
81
static mut HTTP2_MAX_FRAMES: usize = 65536;
82
pub(super) static mut HTTP2_COMPRESSION_BOMB_LIMIT: u64 = 1_048_576;
83
84
#[derive(AppLayerFrameType)]
85
pub enum Http2FrameType {
86
    Hdr,
87
    Data,
88
    Pdu,
89
}
90
91
#[repr(u8)]
92
#[derive(Copy, Clone, PartialOrd, PartialEq, Eq, Debug)]
93
pub enum HTTP2FrameUnhandledReason {
94
    UnknownType = 0,
95
    TooLong = 1,
96
    ParsingError = 2,
97
    Incomplete = 3,
98
}
99
100
impl fmt::Display for HTTP2FrameUnhandledReason {
101
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102
0
        write!(f, "{:?}", self)
103
0
    }
104
}
105
106
#[derive(Debug)]
107
pub struct HTTP2FrameUnhandled {
108
    pub reason: HTTP2FrameUnhandledReason,
109
}
110
111
#[derive(Debug)]
112
pub enum HTTP2FrameTypeData {
113
    PRIORITY(parser::HTTP2FramePriority),
114
    GOAWAY(parser::HTTP2FrameGoAway),
115
    RSTSTREAM(parser::HTTP2FrameRstStream),
116
    SETTINGS(Vec<parser::HTTP2FrameSettings>),
117
    WINDOWUPDATE(parser::HTTP2FrameWindowUpdate),
118
    HEADERS(parser::HTTP2FrameHeaders),
119
    PUSHPROMISE(parser::HTTP2FramePushPromise),
120
    CONTINUATION(parser::HTTP2FrameContinuation),
121
    PING,
122
    DATA,
123
    //not a defined frame
124
    UNHANDLED(HTTP2FrameUnhandled),
125
}
126
127
#[repr(u8)]
128
#[derive(Copy, Clone, PartialOrd, PartialEq, Eq, Debug)]
129
pub enum HTTP2TransactionState {
130
    HTTP2StateIdle = 0,
131
    HTTP2StateOpen = 1,
132
    HTTP2StateReserved = 2,
133
    HTTP2StateDataClient = 3,
134
    HTTP2StateHalfClosedClient = 4,
135
    HTTP2StateDataServer = 5,
136
    HTTP2StateHalfClosedServer = 6,
137
    HTTP2StateClosed = 7,
138
    //not a RFC-defined state, used for stream 0 frames applying to the global connection
139
    HTTP2StateGlobal = 8,
140
    //not a RFC-defined state, dropping this old tx because we have too many
141
    HTTP2StateTodrop = 9,
142
}
143
144
#[derive(Debug)]
145
pub struct HTTP2Frame {
146
    pub header: parser::HTTP2FrameHeader,
147
    pub data: HTTP2FrameTypeData,
148
}
149
150
#[derive(Debug, Default)]
151
/// Dns Over HTTP2 Data inside a HTTP2 transaction
152
pub struct DohHttp2Tx {
153
    /// wether the HTTP2 data is DNS, for both directions
154
    is_doh_data: [bool; 2],
155
    /// http2 data buffer to parse as DNS on completion
156
    pub data_buf: [Vec<u8>; 2],
157
    /// dns request transation
158
    pub dns_request_tx: Option<DNSTransaction>,
159
    /// dns response transation
160
    pub dns_response_tx: Option<DNSTransaction>,
161
}
162
163
#[derive(Debug)]
164
pub struct HTTP2Transaction {
165
    tx_id: u64,
166
    pub stream_id: u32,
167
    pub state: HTTP2TransactionState,
168
    child_stream_id: u32,
169
170
    pub frames_tc: Vec<HTTP2Frame>,
171
    pub frames_ts: Vec<HTTP2Frame>,
172
173
    decoder: decompression::HTTP2Decoder,
174
    pub file_range: *mut HttpRangeContainerBlock,
175
176
    pub tx_data: AppLayerTxData,
177
    pub ft_tc: FileTransferTracker,
178
    pub ft_ts: FileTransferTracker,
179
180
    pub req_line: Vec<u8>,
181
    pub resp_line: Vec<u8>,
182
183
    pub doh: Option<DohHttp2Tx>,
184
}
185
186
impl Transaction for HTTP2Transaction {
187
191M
    fn id(&self) -> u64 {
188
191M
        self.tx_id
189
191M
    }
190
}
191
192
impl Default for HTTP2Transaction {
193
0
    fn default() -> Self {
194
0
        Self::new()
195
0
    }
196
}
197
198
impl HTTP2Transaction {
199
2.40M
    pub fn new() -> Self {
200
2.40M
        Self {
201
2.40M
            tx_id: 0,
202
2.40M
            stream_id: 0,
203
2.40M
            child_stream_id: 0,
204
2.40M
            state: HTTP2TransactionState::HTTP2StateIdle,
205
2.40M
            frames_tc: Vec::new(),
206
2.40M
            frames_ts: Vec::new(),
207
2.40M
            decoder: decompression::HTTP2Decoder::new(),
208
2.40M
            file_range: std::ptr::null_mut(),
209
2.40M
            tx_data: AppLayerTxData::new(),
210
2.40M
            ft_tc: FileTransferTracker::new(),
211
2.40M
            ft_ts: FileTransferTracker::new(),
212
2.40M
            req_line: Vec::new(),
213
2.40M
            resp_line: Vec::new(),
214
2.40M
            doh: None,
215
2.40M
        }
216
2.40M
    }
217
218
2.40M
    pub fn free(&mut self) {
219
2.40M
        if !self.file_range.is_null() {
220
0
            if let Some(c) = unsafe { SC } {
221
0
                if let Some(sfcm) = unsafe { SURICATA_HTTP2_FILE_CONFIG } {
222
0
                    //TODO get a file container instead of NULL
223
0
                    (c.HTPFileCloseHandleRange)(
224
0
                        sfcm.files_sbcfg,
225
0
                        std::ptr::null_mut(),
226
0
                        0,
227
0
                        self.file_range,
228
0
                        std::ptr::null_mut(),
229
0
                        0,
230
0
                    );
231
0
                    (c.HttpRangeFreeBlock)(self.file_range);
232
0
                    self.file_range = std::ptr::null_mut();
233
0
                }
234
0
            }
235
2.40M
        }
236
2.40M
    }
237
238
13.5M
    pub fn set_event(&mut self, event: HTTP2Event) {
239
13.5M
        self.tx_data.set_event(event as u8);
240
13.5M
    }
241
242
956k
    fn handle_headers(
243
956k
        &mut self, blocks: &[parser::HTTP2FrameHeaderBlock], dir: Direction,
244
956k
    ) -> Option<Vec<u8>> {
245
956k
        let mut authority = None;
246
956k
        let mut path = None;
247
956k
        let mut doh = false;
248
956k
        let mut host = None;
249
28.3M
        for block in blocks {
250
27.3M
            if block.name.as_ref() == b"content-encoding" {
251
43.6k
                self.decoder.http2_encoding_fromvec(&block.value, dir);
252
27.3M
            } else if block.name.as_ref() == b"accept" {
253
                //TODO? faster pattern matching
254
346k
                if block.value.as_ref() == b"application/dns-message" {
255
0
                    doh = true;
256
346k
                }
257
26.9M
            } else if block.name.as_ref() == b"content-type" {
258
27.0k
                if block.value.as_ref() == b"application/dns-message" {
259
273
                    if let Some(doh) = &mut self.doh {
260
237
                        doh.is_doh_data[dir.index()] = true;
261
237
                    } else {
262
36
                        let mut doh = DohHttp2Tx::default();
263
36
                        doh.is_doh_data[dir.index()] = true;
264
36
                        self.doh = Some(doh);
265
36
                    }
266
26.7k
                }
267
26.9M
            } else if block.name.as_ref() == b":path" {
268
402k
                path = Some(&block.value);
269
26.5M
            } else if block.name.eq_ignore_ascii_case(b":authority") {
270
915k
                authority = Some(&block.value);
271
915k
                if block.value.contains(&b'@') {
272
115k
                    // it is forbidden by RFC 9113 to have userinfo in this field
273
115k
                    // when in HTTP1 we can have user:password@domain.com
274
115k
                    self.set_event(HTTP2Event::UserinfoInUri);
275
800k
                }
276
25.6M
            } else if block.name.eq_ignore_ascii_case(b"host") {
277
146k
                host = Some(&block.value);
278
25.4M
            }
279
        }
280
956k
        if let Some(a) = authority {
281
164k
            if let Some(h) = host {
282
21.9k
                if !a.eq_ignore_ascii_case(h) {
283
21.3k
                    // The event is triggered only if both headers
284
21.3k
                    // are in the same frame to avoid excessive
285
21.3k
                    // complexity at runtime.
286
21.3k
                    self.set_event(HTTP2Event::AuthorityHostMismatch);
287
21.3k
                }
288
142k
            }
289
791k
        }
290
956k
        if doh && unsafe { ALPROTO_DOH2 } != ALPROTO_UNKNOWN {
291
0
            if let Some(p) = path {
292
0
                if let Ok((_, dns_req)) = parser::doh_extract_request(p) {
293
0
                    return Some(dns_req);
294
0
                }
295
0
            }
296
956k
        }
297
956k
        return None;
298
956k
    }
299
300
5.27M
    pub fn update_file_flags(&mut self, flow_file_flags: u16) {
301
5.27M
        self.ft_ts.file_flags = unsafe { FileFlowFlagsToFlags(flow_file_flags, STREAM_TOSERVER) };
302
5.27M
        self.ft_tc.file_flags = unsafe { FileFlowFlagsToFlags(flow_file_flags, STREAM_TOCLIENT) };
303
5.27M
    }
304
305
3.27M
    fn decompress<'a>(
306
3.27M
        &'a mut self, input: &'a [u8], output: &'a mut Vec<u8>, dir: Direction,
307
3.27M
        sfcm: &'static SuricataFileContext, over: bool, flow: *const Flow,
308
3.27M
    ) -> io::Result<()> {
309
3.27M
        let decompressed = self.decoder.decompress(input, output, dir)?;
310
3.26M
        let xid: u32 = self.tx_id as u32;
311
3.26M
        if dir == Direction::ToClient {
312
1.38M
            self.ft_tc.tx_id = self.tx_id - 1;
313
            // Check that we are at the beginning of the file
314
1.38M
            if !self.ft_tc.is_initialized() {
315
                // we are now sure that new_chunk will open a file
316
                // even if it may close it right afterwards
317
210k
                self.tx_data.incr_files_opened();
318
210k
                if let Ok(value) = detect::http2_frames_get_header_value_vec(
319
210k
                    self,
320
210k
                    Direction::ToClient,
321
210k
                    "content-range",
322
210k
                ) {
323
44.1k
                    match range::http2_parse_check_content_range(&value) {
324
32.0k
                        Ok((_, v)) => {
325
32.0k
                            range::http2_range_open(
326
32.0k
                                self,
327
32.0k
                                &v,
328
32.0k
                                flow,
329
32.0k
                                sfcm,
330
32.0k
                                Direction::ToClient,
331
32.0k
                                decompressed,
332
                            );
333
32.0k
                            if over && !self.file_range.is_null() {
334
6.23k
                                range::http2_range_close(self, Direction::ToClient, &[])
335
25.7k
                            }
336
                        }
337
12.1k
                        _ => {
338
12.1k
                            self.set_event(HTTP2Event::InvalidRange);
339
12.1k
                        }
340
                    }
341
166k
                }
342
1.17M
            } else if !self.file_range.is_null() {
343
20.4k
                if over {
344
12.3k
                    range::http2_range_close(self, Direction::ToClient, decompressed)
345
                } else {
346
8.03k
                    range::http2_range_append(sfcm, self.file_range, decompressed)
347
                }
348
1.15M
            }
349
1.38M
            self.ft_tc.new_chunk(
350
1.38M
                sfcm,
351
1.38M
                b"",
352
1.38M
                decompressed,
353
1.38M
                self.ft_tc.tracked, //offset = append
354
1.38M
                decompressed.len() as u32,
355
                0,
356
1.38M
                over,
357
1.38M
                &xid,
358
            );
359
        } else {
360
1.88M
            self.ft_ts.tx_id = self.tx_id - 1;
361
1.88M
            if !self.ft_ts.file_open {
362
1.12M
                self.tx_data.incr_files_opened();
363
1.12M
            }
364
1.88M
            self.ft_ts.new_chunk(
365
1.88M
                sfcm,
366
1.88M
                b"",
367
1.88M
                decompressed,
368
1.88M
                self.ft_ts.tracked, //offset = append
369
1.88M
                decompressed.len() as u32,
370
                0,
371
1.88M
                over,
372
1.88M
                &xid,
373
            );
374
        };
375
3.26M
        if unsafe { ALPROTO_DOH2 } != ALPROTO_UNKNOWN {
376
            // we store DNS response, and process it when complete
377
3.26M
            if let Some(doh) = &mut self.doh {
378
1.10k
                if doh.is_doh_data[dir.index()] {
379
0
                    if doh.data_buf[dir.index()].len() + decompressed.len() <= 0xFFFF {
380
0
                        // a DNS message is U16_MAX
381
0
                        doh.data_buf[dir.index()].extend_from_slice(decompressed);
382
0
                    } else {
383
                        // stop processing further data
384
0
                        doh.is_doh_data[dir.index()] = false;
385
0
                        if dir == Direction::ToClient {
386
0
                            self.set_event(HTTP2Event::DnsResponseTooLong);
387
0
                        } else {
388
0
                            self.set_event(HTTP2Event::DnsRequestTooLong);
389
0
                        }
390
                    }
391
1.10k
                }
392
3.26M
            }
393
0
        }
394
3.26M
        return Ok(());
395
3.27M
    }
396
397
7.41M
    fn handle_frame(
398
7.41M
        &mut self, header: &parser::HTTP2FrameHeader, data: &HTTP2FrameTypeData, dir: Direction,
399
7.41M
    ) -> Option<Vec<u8>> {
400
        //handle child_stream_id changes
401
7.41M
        let mut r = None;
402
7.41M
        match data {
403
9.97k
            HTTP2FrameTypeData::PUSHPROMISE(hs) => {
404
9.97k
                if dir == Direction::ToClient {
405
                    //we could set an event if self.child_stream_id != 0
406
4.94k
                    if header.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS == 0 {
407
2.41k
                        self.child_stream_id = hs.stream_id;
408
2.52k
                    }
409
4.94k
                    self.state = HTTP2TransactionState::HTTP2StateReserved;
410
5.03k
                }
411
9.97k
                r = self.handle_headers(&hs.blocks, dir);
412
            }
413
835k
            HTTP2FrameTypeData::CONTINUATION(hs) => {
414
835k
                if dir == Direction::ToClient
415
520k
                    && header.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS != 0
416
5.40k
                {
417
5.40k
                    self.child_stream_id = 0;
418
829k
                }
419
835k
                r = self.handle_headers(&hs.blocks, dir);
420
            }
421
110k
            HTTP2FrameTypeData::HEADERS(hs) => {
422
110k
                if dir == Direction::ToClient {
423
23.9k
                    self.child_stream_id = 0;
424
86.9k
                }
425
110k
                r = self.handle_headers(&hs.blocks, dir);
426
            }
427
7.46k
            HTTP2FrameTypeData::RSTSTREAM(_) => {
428
7.46k
                self.child_stream_id = 0;
429
7.46k
            }
430
6.45M
            _ => {}
431
        }
432
        //handle closing state changes
433
7.41M
        match data {
434
            HTTP2FrameTypeData::HEADERS(_) | HTTP2FrameTypeData::DATA => {
435
5.03M
                if header.flags & parser::HTTP2_FLAG_HEADER_EOS != 0 {
436
1.66M
                    match self.state {
437
                        HTTP2TransactionState::HTTP2StateHalfClosedClient
438
                        | HTTP2TransactionState::HTTP2StateDataServer => {
439
1.03M
                            if dir == Direction::ToClient {
440
130k
                                self.state = HTTP2TransactionState::HTTP2StateClosed;
441
908k
                            }
442
                        }
443
                        HTTP2TransactionState::HTTP2StateHalfClosedServer => {
444
207k
                            if dir == Direction::ToServer {
445
65.2k
                                self.state = HTTP2TransactionState::HTTP2StateClosed;
446
142k
                            }
447
                        }
448
                        // do not revert back to a half closed state
449
24.8k
                        HTTP2TransactionState::HTTP2StateClosed => {}
450
211k
                        HTTP2TransactionState::HTTP2StateGlobal => {}
451
                        _ => {
452
184k
                            if dir == Direction::ToClient {
453
69.8k
                                self.state = HTTP2TransactionState::HTTP2StateHalfClosedServer;
454
114k
                            } else {
455
114k
                                self.state = HTTP2TransactionState::HTTP2StateHalfClosedClient;
456
114k
                            }
457
                        }
458
                    }
459
3.36M
                } else if header.ftype == parser::HTTP2FrameType::Data as u8 {
460
                    //not end of stream
461
3.27M
                    if dir == Direction::ToServer {
462
1.44M
                        if self.state < HTTP2TransactionState::HTTP2StateDataClient {
463
21.5k
                            self.state = HTTP2TransactionState::HTTP2StateDataClient;
464
1.42M
                        }
465
1.82M
                    } else if self.state < HTTP2TransactionState::HTTP2StateDataServer {
466
43.1k
                        self.state = HTTP2TransactionState::HTTP2StateDataServer;
467
1.78M
                    }
468
91.0k
                }
469
            }
470
2.38M
            _ => {}
471
        }
472
7.41M
        return r;
473
7.41M
    }
474
475
1.43M
    fn handle_dns_data(&mut self, dir: Direction, flow: *mut Flow) {
476
1.43M
        if let Some(doh) = &mut self.doh {
477
547
            if !doh.data_buf[dir.index()].is_empty() {
478
0
                if dir.is_to_client() {
479
0
                    if let Ok(mut dtx) = dns_parse_response(&doh.data_buf[dir.index()]) {
480
0
                        dtx.id = 1;
481
0
                        doh.dns_response_tx = Some(dtx);
482
0
                        unsafe {
483
0
                            SCAppLayerForceProtocolChange(flow, ALPROTO_DOH2);
484
0
                        }
485
0
                    }
486
0
                } else if let Ok(mut dtx) =
487
0
                    dns_parse_request(&doh.data_buf[dir.index()], &DnsVariant::Dns)
488
                {
489
0
                    dtx.id = 1;
490
0
                    doh.dns_request_tx = Some(dtx);
491
0
                    unsafe {
492
0
                        SCAppLayerForceProtocolChange(flow, ALPROTO_DOH2);
493
0
                    }
494
0
                }
495
0
                doh.data_buf[dir.index()].clear();
496
547
            }
497
1.43M
        }
498
1.43M
    }
499
500
3.27M
    fn handle_data_frame(
501
3.27M
        &mut self, rem: &[u8], hlsafe: usize, dir: Direction, flow: *mut Flow, padded: bool,
502
3.27M
        over: bool,
503
3.27M
    ) {
504
3.27M
        match unsafe { SURICATA_HTTP2_FILE_CONFIG } {
505
3.27M
            Some(sfcm) => {
506
3.27M
                if dir == Direction::ToServer {
507
1.88M
                    self.ft_tc.tx_id = self.tx_id - 1;
508
1.88M
                } else {
509
1.38M
                    self.ft_ts.tx_id = self.tx_id - 1;
510
1.38M
                };
511
3.27M
                let mut dinput = &rem[..hlsafe];
512
3.27M
                if padded && !rem.is_empty() && usize::from(rem[0]) < hlsafe {
513
6.28k
                    dinput = &rem[1..hlsafe - usize::from(rem[0])];
514
3.26M
                }
515
3.27M
                let mut output = Vec::with_capacity(decompression::HTTP2_DECOMPRESSION_CHUNK_SIZE);
516
3.27M
                match self.decompress(dinput, &mut output, dir, sfcm, over, flow) {
517
                    Ok(_) => {
518
3.26M
                        if over {
519
1.43M
                            self.handle_dns_data(dir, flow);
520
1.83M
                        }
521
                    }
522
1.27k
                    Err(e) => {
523
1.27k
                        if e.kind() == io::ErrorKind::OutOfMemory {
524
0
                            self.set_event(HTTP2Event::CompressionBomb);
525
1.27k
                        } else {
526
1.27k
                            self.set_event(HTTP2Event::FailedDecompression);
527
1.27k
                        }
528
                    }
529
                }
530
            }
531
0
            None => panic!("no SURICATA_HTTP2_FILE_CONFIG"),
532
        }
533
3.27M
    }
534
}
535
536
impl Drop for HTTP2Transaction {
537
2.40M
    fn drop(&mut self) {
538
2.40M
        if let Some(sfcm) = unsafe { SURICATA_HTTP2_FILE_CONFIG } {
539
2.40M
            self.ft_ts.file.free(sfcm);
540
2.40M
            self.ft_tc.file.free(sfcm);
541
2.40M
        }
542
2.40M
        self.free();
543
2.40M
    }
544
}
545
546
#[derive(AppLayerEvent)]
547
pub enum HTTP2Event {
548
    InvalidFrameHeader,
549
    InvalidClientMagic,
550
    InvalidFrameData,
551
    InvalidHeader,
552
    InvalidFrameLength,
553
    ExtraHeaderData,
554
    LongFrameData,
555
    StreamIdReuse,
556
    InvalidHttp1Settings,
557
    FailedDecompression,
558
    InvalidRange,
559
    HeaderIntegerOverflow,
560
    HeaderTableOverflow,
561
    TooManyStreams,
562
    AuthorityHostMismatch,
563
    UserinfoInUri,
564
    ReassemblyLimitReached,
565
    DnsRequestTooLong,
566
    DnsResponseTooLong,
567
    DataStreamZero,
568
    TooManyFrames,
569
    CompressionBomb,
570
}
571
572
pub struct HTTP2DynTable {
573
    pub table: Vec<parser::HTTP2FrameHeaderBlock>,
574
    pub current_size: usize,
575
    pub max_size: usize,
576
    pub overflow: u8,
577
}
578
579
impl Default for HTTP2DynTable {
580
0
    fn default() -> Self {
581
0
        Self::new()
582
0
    }
583
}
584
585
impl HTTP2DynTable {
586
28.5k
    pub fn new() -> Self {
587
28.5k
        Self {
588
28.5k
            table: Vec::with_capacity(64),
589
28.5k
            current_size: 0,
590
28.5k
            max_size: 4096, //default value
591
28.5k
            overflow: 0,
592
28.5k
        }
593
28.5k
    }
594
}
595
596
#[derive(Default)]
597
struct HTTP2HeaderReassemblyBuffer {
598
    data: Vec<u8>,
599
    stream_id: u32,
600
}
601
602
pub struct HTTP2State {
603
    state_data: AppLayerStateData,
604
    tx_id: u64,
605
    request_frame_size: u32,
606
    response_frame_size: u32,
607
    dynamic_headers_ts: HTTP2DynTable,
608
    dynamic_headers_tc: HTTP2DynTable,
609
    transactions: VecDeque<HTTP2Transaction>,
610
    progress: HTTP2ConnectionState,
611
612
    comp_len: u64,
613
    decomp_len: u64,
614
615
    c2s_buf: HTTP2HeaderReassemblyBuffer,
616
    s2c_buf: HTTP2HeaderReassemblyBuffer,
617
}
618
619
impl State<HTTP2Transaction> for HTTP2State {
620
65.3M
    fn get_transaction_count(&self) -> usize {
621
65.3M
        self.transactions.len()
622
65.3M
    }
623
624
126M
    fn get_transaction_by_index(&self, index: usize) -> Option<&HTTP2Transaction> {
625
126M
        self.transactions.get(index)
626
126M
    }
627
}
628
629
impl Default for HTTP2State {
630
0
    fn default() -> Self {
631
0
        Self::new()
632
0
    }
633
}
634
635
impl HTTP2State {
636
14.2k
    pub fn new() -> Self {
637
14.2k
        Self {
638
14.2k
            state_data: AppLayerStateData::new(),
639
14.2k
            tx_id: 0,
640
14.2k
            request_frame_size: 0,
641
14.2k
            response_frame_size: 0,
642
14.2k
            // the headers are encoded on one byte
643
14.2k
            // with a fixed number of static headers, and
644
14.2k
            // a variable number of dynamic headers
645
14.2k
            dynamic_headers_ts: HTTP2DynTable::new(),
646
14.2k
            dynamic_headers_tc: HTTP2DynTable::new(),
647
14.2k
            transactions: VecDeque::new(),
648
14.2k
            progress: HTTP2ConnectionState::Http2StateInit,
649
14.2k
            comp_len: 0,
650
14.2k
            decomp_len: 0,
651
14.2k
            c2s_buf: HTTP2HeaderReassemblyBuffer::default(),
652
14.2k
            s2c_buf: HTTP2HeaderReassemblyBuffer::default(),
653
14.2k
        }
654
14.2k
    }
655
656
14.2k
    pub fn free(&mut self) {
657
        // this should be in HTTP2Transaction::free
658
        // but we need state's file container cf https://redmine.openinfosecfoundation.org/issues/4444
659
324k
        for tx in &mut self.transactions {
660
310k
            if !tx.file_range.is_null() {
661
962
                if let Some(c) = unsafe { SC } {
662
962
                    if let Some(sfcm) = unsafe { SURICATA_HTTP2_FILE_CONFIG } {
663
962
                        (c.HTPFileCloseHandleRange)(
664
962
                            sfcm.files_sbcfg,
665
962
                            &mut tx.ft_tc.file,
666
962
                            0,
667
962
                            tx.file_range,
668
962
                            std::ptr::null_mut(),
669
962
                            0,
670
962
                        );
671
962
                        (c.HttpRangeFreeBlock)(tx.file_range);
672
962
                        tx.file_range = std::ptr::null_mut();
673
962
                    }
674
0
                }
675
309k
            }
676
        }
677
14.2k
        self.transactions.clear();
678
14.2k
    }
679
680
43.1k
    pub fn set_event(&mut self, event: HTTP2Event) {
681
43.1k
        let len = self.transactions.len();
682
43.1k
        if len == 0 {
683
11.8k
            return;
684
31.2k
        }
685
31.2k
        let tx = &mut self.transactions[len - 1];
686
31.2k
        tx.tx_data.set_event(event as u8);
687
43.1k
    }
688
689
    // Free a transaction by ID.
690
2.09M
    fn free_tx(&mut self, tx_id: u64) {
691
2.09M
        let len = self.transactions.len();
692
2.09M
        let mut found = false;
693
2.09M
        let mut index = 0;
694
28.5M
        for i in 0..len {
695
28.5M
            let tx = &mut self.transactions[i];
696
28.5M
            if tx.tx_id == tx_id + 1 {
697
2.09M
                found = true;
698
2.09M
                index = i;
699
                // this should be in HTTP2Transaction::free
700
                // but we need state's file container cf https://redmine.openinfosecfoundation.org/issues/4444
701
2.09M
                if !tx.file_range.is_null() {
702
85
                    if let Some(c) = unsafe { SC } {
703
85
                        if let Some(sfcm) = unsafe { SURICATA_HTTP2_FILE_CONFIG } {
704
85
                            (c.HTPFileCloseHandleRange)(
705
85
                                sfcm.files_sbcfg,
706
85
                                &mut tx.ft_tc.file,
707
85
                                0,
708
85
                                tx.file_range,
709
85
                                std::ptr::null_mut(),
710
85
                                0,
711
85
                            );
712
85
                            (c.HttpRangeFreeBlock)(tx.file_range);
713
85
                            tx.file_range = std::ptr::null_mut();
714
85
                        }
715
0
                    }
716
2.09M
                }
717
2.09M
                break;
718
26.4M
            }
719
        }
720
2.09M
        if found {
721
2.09M
            self.transactions.remove(index);
722
2.09M
        }
723
2.09M
    }
724
725
0
    pub fn get_tx(&mut self, tx_id: u64) -> Option<&HTTP2Transaction> {
726
0
        for tx in &mut self.transactions {
727
0
            if tx.tx_id == tx_id + 1 {
728
0
                tx.tx_data.update_file_flags(self.state_data.file_flags);
729
0
                tx.update_file_flags(tx.tx_data.file_flags);
730
0
                return Some(tx);
731
0
            }
732
        }
733
0
        return None;
734
0
    }
735
736
5.27M
    fn find_tx_index(&mut self, sid: u32) -> usize {
737
47.5M
        for i in 0..self.transactions.len() {
738
            //reverse order should be faster
739
47.5M
            let idx = self.transactions.len() - 1 - i;
740
47.5M
            if sid == self.transactions[idx].stream_id {
741
5.00M
                return idx + 1;
742
42.5M
            }
743
        }
744
266k
        return 0;
745
5.27M
    }
746
747
452k
    fn find_child_stream_id(&mut self, sid: u32) -> u32 {
748
2.15M
        for i in 0..self.transactions.len() {
749
            //reverse order should be faster
750
2.15M
            if sid == self.transactions[self.transactions.len() - 1 - i].stream_id {
751
427k
                if self.transactions[self.transactions.len() - 1 - i].child_stream_id > 0 {
752
0
                    return self.transactions[self.transactions.len() - 1 - i].child_stream_id;
753
427k
                }
754
427k
                return sid;
755
1.73M
            }
756
        }
757
24.1k
        return sid;
758
452k
    }
759
760
2.14M
    fn create_global_tx(&mut self) -> &mut HTTP2Transaction {
761
        //special transaction with only one frame
762
        //as it affects the global connection, there is no end to it
763
2.14M
        let mut tx = HTTP2Transaction::new();
764
2.14M
        self.tx_id += 1;
765
2.14M
        tx.tx_id = self.tx_id;
766
2.14M
        tx.state = HTTP2TransactionState::HTTP2StateGlobal;
767
        // a global tx (stream id 0) does not hold files cf RFC 9113 section 5.1.1
768
2.14M
        self.transactions.push_back(tx);
769
2.14M
        return self.transactions.back_mut().unwrap();
770
2.14M
    }
771
772
7.41M
    pub fn find_or_create_tx(
773
7.41M
        &mut self, header: &parser::HTTP2FrameHeader, data: &HTTP2FrameTypeData, dir: Direction,
774
7.41M
    ) -> Option<&mut HTTP2Transaction> {
775
7.41M
        if header.stream_id == 0 {
776
2.14M
            if self.transactions.len() >= unsafe { HTTP2_MAX_STREAMS } {
777
143k
                for tx_old in &mut self.transactions {
778
143k
                    if tx_old.state == HTTP2TransactionState::HTTP2StateTodrop {
779
                        // loop was already run
780
0
                        break;
781
143k
                    }
782
143k
                    tx_old.set_event(HTTP2Event::TooManyStreams);
783
                    // use a distinct state, even if we do not log it
784
143k
                    tx_old.state = HTTP2TransactionState::HTTP2StateTodrop;
785
143k
                    tx_old.tx_data.updated_tc = true;
786
143k
                    tx_old.tx_data.updated_ts = true;
787
                }
788
35
                return None;
789
2.14M
            }
790
2.14M
            return Some(self.create_global_tx());
791
5.27M
        }
792
5.27M
        let sid = match data {
793
            //yes, the right stream_id for Suricata is not the header one
794
9.60k
            HTTP2FrameTypeData::PUSHPROMISE(hs) => hs.stream_id,
795
            HTTP2FrameTypeData::CONTINUATION(_) => {
796
678k
                if dir == Direction::ToClient {
797
                    //continuation of a push promise
798
452k
                    self.find_child_stream_id(header.stream_id)
799
                } else {
800
226k
                    header.stream_id
801
                }
802
            }
803
4.58M
            _ => header.stream_id,
804
        };
805
5.27M
        let index = self.find_tx_index(sid);
806
5.27M
        if index > 0 {
807
5.00M
            if self.transactions[index - 1].state == HTTP2TransactionState::HTTP2StateClosed {
808
                //these frames can be received in this state for a short period
809
28.0k
                if header.ftype != parser::HTTP2FrameType::RstStream as u8
810
27.5k
                    && header.ftype != parser::HTTP2FrameType::WindowUpdate as u8
811
26.5k
                    && header.ftype != parser::HTTP2FrameType::Priority as u8
812
25.8k
                {
813
25.8k
                    self.set_event(HTTP2Event::StreamIdReuse);
814
25.8k
                }
815
4.98M
            }
816
817
5.00M
            let tx = &mut self.transactions[index - 1];
818
5.00M
            tx.tx_data.update_file_flags(self.state_data.file_flags);
819
5.00M
            tx.update_file_flags(tx.tx_data.file_flags);
820
5.00M
            tx.tx_data.updated_tc = true;
821
5.00M
            tx.tx_data.updated_ts = true;
822
5.00M
            return Some(tx);
823
        } else {
824
            // do not use SETTINGS_MAX_CONCURRENT_STREAMS as it can grow too much
825
266k
            if self.transactions.len() >= unsafe { HTTP2_MAX_STREAMS } {
826
16.3k
                for tx_old in &mut self.transactions {
827
16.3k
                    if tx_old.state == HTTP2TransactionState::HTTP2StateTodrop {
828
                        // loop was already run
829
0
                        break;
830
16.3k
                    }
831
16.3k
                    tx_old.set_event(HTTP2Event::TooManyStreams);
832
                    // use a distinct state, even if we do not log it
833
16.3k
                    tx_old.state = HTTP2TransactionState::HTTP2StateTodrop;
834
16.3k
                    tx_old.tx_data.updated_tc = true;
835
16.3k
                    tx_old.tx_data.updated_ts = true;
836
                }
837
4
                return None;
838
266k
            }
839
266k
            let mut tx = HTTP2Transaction::new();
840
266k
            self.tx_id += 1;
841
266k
            tx.tx_id = self.tx_id;
842
266k
            tx.stream_id = sid;
843
266k
            tx.state = HTTP2TransactionState::HTTP2StateOpen;
844
266k
            tx.tx_data.update_file_flags(self.state_data.file_flags);
845
266k
            tx.update_file_flags(tx.tx_data.file_flags);
846
266k
            tx.tx_data.file_tx = STREAM_TOSERVER | STREAM_TOCLIENT; // might hold files in both directions
847
266k
            self.transactions.push_back(tx);
848
266k
            return Some(self.transactions.back_mut().unwrap());
849
        }
850
7.41M
    }
851
852
695k
    fn process_headers(
853
695k
        &mut self, blocks: &Vec<parser::HTTP2FrameHeaderBlock>, dir: Direction,
854
695k
    ) -> Vec<HTTP2Event> {
855
695k
        let mut events = Vec::new();
856
28.0M
        for block in blocks {
857
27.3M
            if block.error >= parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeError {
858
12.3M
                events.push(HTTP2Event::InvalidHeader);
859
15.0M
            } else if block.error
860
15.0M
                == parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeIntegerOverflow
861
0
            {
862
0
                events.push(HTTP2Event::HeaderIntegerOverflow);
863
15.0M
            }
864
        }
865
695k
        let dyn_headers = if dir == Direction::ToClient {
866
458k
            &mut self.dynamic_headers_tc
867
        } else {
868
236k
            &mut self.dynamic_headers_ts
869
        };
870
695k
        if dyn_headers.overflow == 2 {
871
912
            // event only once
872
912
            dyn_headers.overflow = 3;
873
912
            events.push(HTTP2Event::HeaderTableOverflow);
874
694k
        }
875
695k
        return events;
876
695k
    }
877
878
7.41M
    fn parse_frame_data(
879
7.41M
        &mut self, head: &parser::HTTP2FrameHeader, input: &[u8], complete: bool, dir: Direction,
880
7.41M
        reass_limit_reached: &mut bool,
881
7.41M
    ) -> (HTTP2FrameTypeData, Vec<HTTP2Event>) {
882
7.41M
        let ftype = head.ftype;
883
7.41M
        let hflags = head.flags;
884
7.41M
        let mut events = Vec::new();
885
7.41M
        match num::FromPrimitive::from_u8(ftype) {
886
            Some(parser::HTTP2FrameType::GoAway) => {
887
36.7k
                if input.len() < HTTP2_FRAME_GOAWAY_LEN {
888
33.3k
                    events.push(HTTP2Event::InvalidFrameLength);
889
33.3k
                    return (
890
33.3k
                        HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
891
33.3k
                            reason: HTTP2FrameUnhandledReason::Incomplete,
892
33.3k
                        }),
893
33.3k
                        events,
894
33.3k
                    );
895
3.36k
                }
896
3.36k
                match parser::http2_parse_frame_goaway(input) {
897
3.36k
                    Ok((_, goaway)) => {
898
3.36k
                        return (HTTP2FrameTypeData::GOAWAY(goaway), events);
899
                    }
900
                    Err(_) => {
901
0
                        events.push(HTTP2Event::InvalidFrameData);
902
0
                        return (
903
0
                            HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
904
0
                                reason: HTTP2FrameUnhandledReason::ParsingError,
905
0
                            }),
906
0
                            events,
907
0
                        );
908
                    }
909
                }
910
            }
911
            Some(parser::HTTP2FrameType::Settings) => {
912
51.9k
                match parser::http2_parse_frame_settings(input) {
913
51.9k
                    Ok((_, set)) => {
914
196k
                        for e in &set {
915
144k
                            if e.id == parser::HTTP2SettingsId::HeaderTableSize {
916
                                //reverse order as this is what we accept from the other endpoint
917
132k
                                let dyn_headers = if dir == Direction::ToClient {
918
123k
                                    &mut self.dynamic_headers_ts
919
                                } else {
920
8.29k
                                    &mut self.dynamic_headers_tc
921
                                };
922
132k
                                dyn_headers.max_size = e.value as usize;
923
132k
                                if e.value > unsafe { HTTP2_MAX_TABLESIZE } {
924
10.2k
                                    //mark potential overflow
925
10.2k
                                    dyn_headers.overflow = 1;
926
122k
                                } else {
927
122k
                                    //reset in case peer set a lower value, to be tested
928
122k
                                    dyn_headers.overflow = 0;
929
122k
                                }
930
11.9k
                            }
931
                        }
932
                        //we could set an event on remaining data
933
51.9k
                        return (HTTP2FrameTypeData::SETTINGS(set), events);
934
                    }
935
                    Err(Err::Incomplete(_)) => {
936
0
                        if complete {
937
0
                            events.push(HTTP2Event::InvalidFrameData);
938
0
                            return (
939
0
                                HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
940
0
                                    reason: HTTP2FrameUnhandledReason::ParsingError,
941
0
                                }),
942
0
                                events,
943
0
                            );
944
                        } else {
945
0
                            return (
946
0
                                HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
947
0
                                    reason: HTTP2FrameUnhandledReason::TooLong,
948
0
                                }),
949
0
                                events,
950
0
                            );
951
                        }
952
                    }
953
                    Err(_) => {
954
0
                        events.push(HTTP2Event::InvalidFrameData);
955
0
                        return (
956
0
                            HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
957
0
                                reason: HTTP2FrameUnhandledReason::ParsingError,
958
0
                            }),
959
0
                            events,
960
0
                        );
961
                    }
962
                }
963
            }
964
            Some(parser::HTTP2FrameType::RstStream) => {
965
9.58k
                if input.len() != HTTP2_FRAME_RSTSTREAM_LEN {
966
2.11k
                    events.push(HTTP2Event::InvalidFrameLength);
967
2.11k
                    return (
968
2.11k
                        HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
969
2.11k
                            reason: HTTP2FrameUnhandledReason::Incomplete,
970
2.11k
                        }),
971
2.11k
                        events,
972
2.11k
                    );
973
                } else {
974
7.46k
                    match parser::http2_parse_frame_rststream(input) {
975
7.46k
                        Ok((_, rst)) => {
976
7.46k
                            return (HTTP2FrameTypeData::RSTSTREAM(rst), events);
977
                        }
978
                        Err(_) => {
979
0
                            events.push(HTTP2Event::InvalidFrameData);
980
0
                            return (
981
0
                                HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
982
0
                                    reason: HTTP2FrameUnhandledReason::ParsingError,
983
0
                                }),
984
0
                                events,
985
0
                            );
986
                        }
987
                    }
988
                }
989
            }
990
            Some(parser::HTTP2FrameType::Priority) => {
991
41.6k
                if input.len() != HTTP2_FRAME_PRIORITY_LEN {
992
25.7k
                    events.push(HTTP2Event::InvalidFrameLength);
993
25.7k
                    return (
994
25.7k
                        HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
995
25.7k
                            reason: HTTP2FrameUnhandledReason::Incomplete,
996
25.7k
                        }),
997
25.7k
                        events,
998
25.7k
                    );
999
                } else {
1000
15.8k
                    match parser::http2_parse_frame_priority(input) {
1001
15.8k
                        Ok((_, priority)) => {
1002
15.8k
                            return (HTTP2FrameTypeData::PRIORITY(priority), events);
1003
                        }
1004
                        Err(_) => {
1005
0
                            events.push(HTTP2Event::InvalidFrameData);
1006
0
                            return (
1007
0
                                HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
1008
0
                                    reason: HTTP2FrameUnhandledReason::ParsingError,
1009
0
                                }),
1010
0
                                events,
1011
0
                            );
1012
                        }
1013
                    }
1014
                }
1015
            }
1016
            Some(parser::HTTP2FrameType::WindowUpdate) => {
1017
327k
                if input.len() != HTTP2_FRAME_WINDOWUPDATE_LEN {
1018
323k
                    events.push(HTTP2Event::InvalidFrameLength);
1019
323k
                    return (
1020
323k
                        HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
1021
323k
                            reason: HTTP2FrameUnhandledReason::Incomplete,
1022
323k
                        }),
1023
323k
                        events,
1024
323k
                    );
1025
                } else {
1026
4.11k
                    match parser::http2_parse_frame_windowupdate(input) {
1027
4.11k
                        Ok((_, wu)) => {
1028
4.11k
                            return (HTTP2FrameTypeData::WINDOWUPDATE(wu), events);
1029
                        }
1030
                        Err(_) => {
1031
0
                            events.push(HTTP2Event::InvalidFrameData);
1032
0
                            return (
1033
0
                                HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
1034
0
                                    reason: HTTP2FrameUnhandledReason::ParsingError,
1035
0
                                }),
1036
0
                                events,
1037
0
                            );
1038
                        }
1039
                    }
1040
                }
1041
            }
1042
            Some(parser::HTTP2FrameType::PushPromise) => {
1043
148k
                let dyn_headers = if dir == Direction::ToClient {
1044
75.5k
                    &mut self.dynamic_headers_tc
1045
                } else {
1046
73.3k
                    &mut self.dynamic_headers_ts
1047
                };
1048
148k
                match parser::http2_parse_frame_push_promise(input, hflags, dyn_headers) {
1049
9.97k
                    Ok((_, hs)) => {
1050
9.97k
                        events.extend(self.process_headers(&hs.blocks, dir));
1051
9.97k
                        return (HTTP2FrameTypeData::PUSHPROMISE(hs), events);
1052
                    }
1053
                    Err(Err::Incomplete(_)) => {
1054
135k
                        if complete {
1055
134k
                            events.push(HTTP2Event::InvalidFrameData);
1056
134k
                            return (
1057
134k
                                HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
1058
134k
                                    reason: HTTP2FrameUnhandledReason::ParsingError,
1059
134k
                                }),
1060
134k
                                events,
1061
134k
                            );
1062
                        } else {
1063
1.69k
                            return (
1064
1.69k
                                HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
1065
1.69k
                                    reason: HTTP2FrameUnhandledReason::TooLong,
1066
1.69k
                                }),
1067
1.69k
                                events,
1068
1.69k
                            );
1069
                        }
1070
                    }
1071
                    Err(_) => {
1072
3.09k
                        events.push(HTTP2Event::InvalidFrameData);
1073
3.09k
                        return (
1074
3.09k
                            HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
1075
3.09k
                                reason: HTTP2FrameUnhandledReason::ParsingError,
1076
3.09k
                            }),
1077
3.09k
                            events,
1078
3.09k
                        );
1079
                    }
1080
                }
1081
            }
1082
            Some(parser::HTTP2FrameType::Data) => {
1083
4.92M
                return (HTTP2FrameTypeData::DATA, events);
1084
            }
1085
            Some(parser::HTTP2FrameType::Continuation) => {
1086
1.06M
                let buf = if dir == Direction::ToClient {
1087
632k
                    &mut self.s2c_buf
1088
                } else {
1089
437k
                    &mut self.c2s_buf
1090
                };
1091
1.06M
                if head.stream_id == buf.stream_id {
1092
188k
                    let max_reass = unsafe { HTTP2_MAX_REASS };
1093
188k
                    if buf.data.len() + input.len() < max_reass {
1094
182k
                        buf.data.extend(input);
1095
182k
                    } else if buf.data.len() < max_reass {
1096
59
                        buf.data.extend(&input[..max_reass - buf.data.len()]);
1097
59
                        *reass_limit_reached = true;
1098
6.23k
                    }
1099
188k
                    if head.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS == 0 {
1100
177k
                        let hs = parser::HTTP2FrameContinuation { blocks: Vec::new() };
1101
177k
                        return (HTTP2FrameTypeData::CONTINUATION(hs), events);
1102
11.6k
                    }
1103
880k
                } // else try to parse anyways
1104
892k
                let input_reass = if head.stream_id == buf.stream_id {
1105
11.6k
                    &buf.data
1106
                } else {
1107
880k
                    input
1108
                };
1109
1110
892k
                let dyn_headers = if dir == Direction::ToClient {
1111
550k
                    &mut self.dynamic_headers_tc
1112
                } else {
1113
341k
                    &mut self.dynamic_headers_ts
1114
                };
1115
892k
                match parser::http2_parse_frame_continuation(input_reass, dyn_headers) {
1116
658k
                    Ok((_, hs)) => {
1117
658k
                        if head.stream_id == buf.stream_id {
1118
2.91k
                            buf.stream_id = 0;
1119
2.91k
                            buf.data.clear();
1120
655k
                        }
1121
658k
                        events.extend(self.process_headers(&hs.blocks, dir));
1122
658k
                        return (HTTP2FrameTypeData::CONTINUATION(hs), events);
1123
                    }
1124
                    Err(Err::Incomplete(_)) => {
1125
234k
                        if head.stream_id == buf.stream_id {
1126
8.77k
                            buf.stream_id = 0;
1127
8.77k
                            buf.data.clear();
1128
225k
                        }
1129
234k
                        if complete {
1130
232k
                            events.push(HTTP2Event::InvalidFrameData);
1131
232k
                            return (
1132
232k
                                HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
1133
232k
                                    reason: HTTP2FrameUnhandledReason::ParsingError,
1134
232k
                                }),
1135
232k
                                events,
1136
232k
                            );
1137
                        } else {
1138
1.44k
                            return (
1139
1.44k
                                HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
1140
1.44k
                                    reason: HTTP2FrameUnhandledReason::TooLong,
1141
1.44k
                                }),
1142
1.44k
                                events,
1143
1.44k
                            );
1144
                        }
1145
                    }
1146
                    Err(_) => {
1147
0
                        if head.stream_id == buf.stream_id {
1148
0
                            buf.stream_id = 0;
1149
0
                            buf.data.clear();
1150
0
                        }
1151
0
                        events.push(HTTP2Event::InvalidFrameData);
1152
0
                        return (
1153
0
                            HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
1154
0
                                reason: HTTP2FrameUnhandledReason::ParsingError,
1155
0
                            }),
1156
0
                            events,
1157
0
                        );
1158
                    }
1159
                }
1160
            }
1161
            Some(parser::HTTP2FrameType::Headers) => {
1162
267k
                if head.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS == 0 {
1163
96.8k
                    let buf = if dir == Direction::ToClient {
1164
12.0k
                        &mut self.s2c_buf
1165
                    } else {
1166
84.7k
                        &mut self.c2s_buf
1167
                    };
1168
96.8k
                    buf.data.clear();
1169
96.8k
                    if let Ok((rem_hpack, hs)) = parser::get_frame_headers_hpack(input, hflags) {
1170
                        // store only the HPACK fragment: skip Pad Length, Priority, and trailing padding
1171
83.8k
                        buf.data.extend(rem_hpack);
1172
83.8k
                        buf.stream_id = head.stream_id;
1173
83.8k
                        return (HTTP2FrameTypeData::HEADERS(hs), events);
1174
                    } else {
1175
12.9k
                        events.push(HTTP2Event::InvalidFrameData);
1176
12.9k
                        return (
1177
12.9k
                            HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
1178
12.9k
                                reason: HTTP2FrameUnhandledReason::ParsingError,
1179
12.9k
                            }),
1180
12.9k
                            events,
1181
12.9k
                        );
1182
                    }
1183
170k
                }
1184
170k
                let dyn_headers = if dir == Direction::ToClient {
1185
53.4k
                    &mut self.dynamic_headers_tc
1186
                } else {
1187
116k
                    &mut self.dynamic_headers_ts
1188
                };
1189
170k
                match parser::http2_parse_frame_headers(input, hflags, dyn_headers) {
1190
27.0k
                    Ok((hrem, hs)) => {
1191
27.0k
                        events.extend(self.process_headers(&hs.blocks, dir));
1192
27.0k
                        if !hrem.is_empty() {
1193
2.00k
                            SCLogDebug!("Remaining data for HTTP2 headers");
1194
2.00k
                            events.push(HTTP2Event::ExtraHeaderData);
1195
25.0k
                        }
1196
27.0k
                        return (HTTP2FrameTypeData::HEADERS(hs), events);
1197
                    }
1198
                    Err(Err::Incomplete(_)) => {
1199
132k
                        if complete {
1200
132k
                            events.push(HTTP2Event::InvalidFrameData);
1201
132k
                            return (
1202
132k
                                HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
1203
132k
                                    reason: HTTP2FrameUnhandledReason::ParsingError,
1204
132k
                                }),
1205
132k
                                events,
1206
132k
                            );
1207
                        } else {
1208
373
                            return (
1209
373
                                HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
1210
373
                                    reason: HTTP2FrameUnhandledReason::TooLong,
1211
373
                                }),
1212
373
                                events,
1213
373
                            );
1214
                        }
1215
                    }
1216
                    Err(_) => {
1217
10.9k
                        events.push(HTTP2Event::InvalidFrameData);
1218
10.9k
                        return (
1219
10.9k
                            HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
1220
10.9k
                                reason: HTTP2FrameUnhandledReason::ParsingError,
1221
10.9k
                            }),
1222
10.9k
                            events,
1223
10.9k
                        );
1224
                    }
1225
                }
1226
            }
1227
            Some(parser::HTTP2FrameType::Ping) => {
1228
69.1k
                return (HTTP2FrameTypeData::PING, events);
1229
            }
1230
            _ => {
1231
473k
                return (
1232
473k
                    HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
1233
473k
                        reason: HTTP2FrameUnhandledReason::UnknownType,
1234
473k
                    }),
1235
473k
                    events,
1236
473k
                );
1237
            }
1238
        }
1239
7.41M
    }
1240
1241
3.45M
    fn parse_frames(
1242
3.45M
        &mut self, mut input: &[u8], il: usize, dir: Direction, flow: *mut Flow,
1243
3.45M
        stream_slice: &StreamSlice,
1244
3.45M
    ) -> AppLayerResult {
1245
10.8M
        while !input.is_empty() {
1246
10.2M
            match parser::http2_parse_frame_header(input) {
1247
8.74M
                Ok((rem, head)) => {
1248
8.74M
                    let hl = head.length as usize;
1249
1250
                    //we check for completeness first
1251
8.74M
                    if rem.len() < hl {
1252
                        //but limit ourselves so as not to exhaust memory
1253
1.33M
                        if hl < HTTP2_MAX_HANDLED_FRAME_SIZE {
1254
591k
                            return AppLayerResult::incomplete(
1255
591k
                                (il - input.len()) as u32,
1256
591k
                                (HTTP2_FRAME_HEADER_LEN + hl) as u32,
1257
                            );
1258
742k
                        } else if rem.len() < HTTP2_MIN_HANDLED_FRAME_SIZE {
1259
735k
                            return AppLayerResult::incomplete(
1260
735k
                                (il - input.len()) as u32,
1261
735k
                                (HTTP2_FRAME_HEADER_LEN + HTTP2_MIN_HANDLED_FRAME_SIZE) as u32,
1262
                            );
1263
                        } else {
1264
6.89k
                            self.set_event(HTTP2Event::LongFrameData);
1265
6.89k
                            if dir == Direction::ToServer {
1266
4.08k
                                self.request_frame_size = head.length - (rem.len() as u32);
1267
4.08k
                            } else {
1268
2.80k
                                self.response_frame_size = head.length - (rem.len() as u32);
1269
2.80k
                            }
1270
                        }
1271
7.41M
                    }
1272
1273
                    //get a safe length for the buffer
1274
7.42M
                    let (hlsafe, complete) = if rem.len() < hl {
1275
6.89k
                        (rem.len(), false)
1276
                    } else {
1277
7.41M
                        (hl, true)
1278
                    };
1279
1280
7.42M
                    let frame_hdr = Frame::new(
1281
7.42M
                        flow,
1282
7.42M
                        stream_slice,
1283
7.42M
                        input,
1284
7.42M
                        HTTP2_FRAME_HEADER_LEN as i64,
1285
7.42M
                        Http2FrameType::Hdr as u8,
1286
7.42M
                        None,
1287
                    );
1288
7.42M
                    let frame_data = Frame::new(
1289
7.42M
                        flow,
1290
7.42M
                        stream_slice,
1291
7.42M
                        &input[HTTP2_FRAME_HEADER_LEN..],
1292
7.42M
                        head.length as i64,
1293
7.42M
                        Http2FrameType::Data as u8,
1294
7.42M
                        None,
1295
                    );
1296
7.42M
                    let frame_pdu = Frame::new(
1297
7.42M
                        flow,
1298
7.42M
                        stream_slice,
1299
7.42M
                        input,
1300
7.42M
                        HTTP2_FRAME_HEADER_LEN as i64 + head.length as i64,
1301
7.42M
                        Http2FrameType::Pdu as u8,
1302
7.42M
                        None,
1303
                    );
1304
7.42M
                    if head.length == 0 && head.ftype == parser::HTTP2FrameType::Settings as u8 {
1305
3.86k
                        input = &rem[hlsafe..];
1306
3.86k
                        continue;
1307
7.41M
                    }
1308
7.41M
                    let mut reass_limit_reached = false;
1309
7.41M
                    let (txdata, events) = self.parse_frame_data(
1310
7.41M
                        &head,
1311
7.41M
                        &rem[..hlsafe],
1312
7.41M
                        complete,
1313
7.41M
                        dir,
1314
7.41M
                        &mut reass_limit_reached,
1315
7.41M
                    );
1316
1317
7.41M
                    let (comp_len, decomp_len) = (self.comp_len, self.decomp_len);
1318
7.41M
                    let tx = self.find_or_create_tx(&head, &txdata, dir);
1319
7.41M
                    if tx.is_none() {
1320
39
                        return AppLayerResult::err();
1321
7.41M
                    }
1322
7.41M
                    let tx = tx.unwrap();
1323
20.6M
                    for event in events {
1324
13.2M
                        tx.set_event(event);
1325
13.2M
                    }
1326
                    SCLogDebug!(
1327
                        "tx stream_id {} tx id {} state {:?}",
1328
                        tx.stream_id,
1329
                        tx.tx_id,
1330
                        tx.state
1331
                    );
1332
7.41M
                    if let Some(frame) = frame_hdr {
1333
0
                        frame.set_tx(flow, tx.tx_id);
1334
7.41M
                    }
1335
7.41M
                    if let Some(frame) = frame_data {
1336
0
                        frame.set_tx(flow, tx.tx_id);
1337
7.41M
                    }
1338
7.41M
                    if let Some(frame) = frame_pdu {
1339
0
                        frame.set_tx(flow, tx.tx_id);
1340
7.41M
                    }
1341
7.41M
                    if let Some(doh_req_buf) = tx.handle_frame(&head, &txdata, dir) {
1342
0
                        if let Ok(mut dtx) = dns_parse_request(&doh_req_buf, &DnsVariant::Dns) {
1343
0
                            dtx.id = 1;
1344
0
                            unsafe {
1345
0
                                SCAppLayerForceProtocolChange(flow, ALPROTO_DOH2);
1346
0
                            }
1347
0
                            if let Some(doh) = &mut tx.doh {
1348
0
                                doh.dns_request_tx = Some(dtx);
1349
0
                            } else {
1350
0
                                let doh = DohHttp2Tx {
1351
0
                                    dns_request_tx: Some(dtx),
1352
0
                                    ..Default::default()
1353
0
                                };
1354
0
                                tx.doh = Some(doh);
1355
0
                            }
1356
0
                        }
1357
7.41M
                    }
1358
7.41M
                    if reass_limit_reached {
1359
59
                        tx.tx_data
1360
59
                            .set_event(HTTP2Event::ReassemblyLimitReached as u8);
1361
7.41M
                    }
1362
7.41M
                    let over = head.flags & parser::HTTP2_FLAG_HEADER_EOS != 0;
1363
7.41M
                    let ftype = head.ftype;
1364
7.41M
                    let sid = head.stream_id;
1365
7.41M
                    let padded = head.flags & parser::HTTP2_FLAG_HEADER_PADDED != 0;
1366
7.41M
                    let h2frames = if dir == Direction::ToServer {
1367
3.74M
                        &mut tx.frames_ts
1368
                    } else {
1369
3.66M
                        &mut tx.frames_tc
1370
                    };
1371
7.41M
                    if h2frames.len() < unsafe { HTTP2_MAX_FRAMES } {
1372
7.24M
                        h2frames.push(HTTP2Frame {
1373
7.24M
                            header: head,
1374
7.24M
                            data: txdata,
1375
7.24M
                        });
1376
7.24M
                    } else {
1377
169k
                        tx.tx_data.set_event(HTTP2Event::TooManyFrames as u8);
1378
169k
                    }
1379
7.41M
                    if ftype == parser::HTTP2FrameType::Data as u8 && sid == 0 {
1380
1.65M
                        tx.tx_data.set_event(HTTP2Event::DataStreamZero as u8);
1381
5.76M
                    } else if ftype == parser::HTTP2FrameType::Data as u8 && sid > 0 {
1382
3.27M
                        tx.handle_data_frame(rem, hlsafe, dir, flow, padded, over);
1383
3.27M
                        let (il, ol) = if dir == Direction::ToClient {
1384
1.38M
                            (
1385
1.38M
                                tx.decoder.decoder_tc.input_len,
1386
1.38M
                                tx.decoder.decoder_tc.output_len,
1387
1.38M
                            )
1388
                        } else {
1389
1.88M
                            (
1390
1.88M
                                tx.decoder.decoder_ts.input_len,
1391
1.88M
                                tx.decoder.decoder_ts.output_len,
1392
1.88M
                            )
1393
                        };
1394
3.27M
                        let (il, ol) = (il + comp_len, ol + decomp_len);
1395
3.27M
                        if ol > decompression::DEFAULT_BOMB_RATIO * il {
1396
0
                            if ol > unsafe { HTTP2_COMPRESSION_BOMB_LIMIT } {
1397
0
                                tx.set_event(HTTP2Event::CompressionBomb);
1398
0
                                return AppLayerResult::err();
1399
0
                            }
1400
0
                            if over {
1401
0
                                self.comp_len += il;
1402
0
                                self.decomp_len += ol;
1403
0
                            }
1404
3.27M
                        }
1405
2.49M
                    }
1406
7.41M
                    sc_app_layer_parser_trigger_raw_stream_inspection(flow, dir as i32);
1407
7.41M
                    input = &rem[hlsafe..];
1408
                }
1409
                Err(Err::Incomplete(_)) => {
1410
                    //we may have consumed data from previous records
1411
1.51M
                    return AppLayerResult::incomplete(
1412
1.51M
                        (il - input.len()) as u32,
1413
1.51M
                        HTTP2_FRAME_HEADER_LEN as u32,
1414
                    );
1415
                }
1416
                Err(_) => {
1417
0
                    self.set_event(HTTP2Event::InvalidFrameHeader);
1418
0
                    return AppLayerResult::err();
1419
                }
1420
            }
1421
        }
1422
603k
        return AppLayerResult::ok();
1423
3.45M
    }
1424
1425
1.92M
    fn parse_ts(&mut self, flow: *mut Flow, stream_slice: StreamSlice) -> AppLayerResult {
1426
        //very first : skip magic
1427
1.92M
        let mut input = stream_slice.as_slice();
1428
1.92M
        let mut magic_consumed = 0;
1429
1.92M
        if self.progress < HTTP2ConnectionState::Http2StateMagicDone {
1430
            //skip magic
1431
60.8k
            if input.len() >= HTTP2_MAGIC_LEN {
1432
                //skip magic
1433
10.6k
                match std::str::from_utf8(&input[..HTTP2_MAGIC_LEN]) {
1434
10.4k
                    Ok("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n") => {
1435
57
                        input = &input[HTTP2_MAGIC_LEN..];
1436
57
                        magic_consumed = HTTP2_MAGIC_LEN;
1437
57
                    }
1438
10.4k
                    Ok(&_) => {
1439
10.4k
                        self.set_event(HTTP2Event::InvalidClientMagic);
1440
10.4k
                    }
1441
                    Err(_) => {
1442
211
                        return AppLayerResult::err();
1443
                    }
1444
                }
1445
10.4k
                self.progress = HTTP2ConnectionState::Http2StateMagicDone;
1446
            } else {
1447
                //still more buffer
1448
50.2k
                return AppLayerResult::incomplete(0_u32, HTTP2_MAGIC_LEN as u32);
1449
            }
1450
1.86M
        }
1451
        //first consume frame bytes
1452
1.87M
        let il = input.len();
1453
1.87M
        if self.request_frame_size > 0 {
1454
188k
            let ilen = input.len() as u32;
1455
188k
            if self.request_frame_size >= ilen {
1456
188k
                self.request_frame_size -= ilen;
1457
188k
                return AppLayerResult::ok();
1458
101
            } else {
1459
101
                let start = self.request_frame_size as usize;
1460
101
                input = &input[start..];
1461
101
                self.request_frame_size = 0;
1462
101
            }
1463
1.68M
        }
1464
1465
        //then parse all we can
1466
1.68M
        let r = self.parse_frames(input, il, Direction::ToServer, flow, &stream_slice);
1467
1.68M
        if r.status == 1 {
1468
            //adds bytes consumed by banner to incomplete result
1469
1.39M
            return AppLayerResult::incomplete(r.consumed + magic_consumed as u32, r.needed);
1470
        } else {
1471
286k
            return r;
1472
        }
1473
1.92M
    }
1474
1475
1.91M
    fn parse_tc(&mut self, flow: *mut Flow, stream_slice: StreamSlice) -> AppLayerResult {
1476
        //first consume frame bytes
1477
1.91M
        let mut input = stream_slice.as_slice();
1478
1.91M
        let il = input.len();
1479
1.91M
        if self.response_frame_size > 0 {
1480
146k
            let ilen = input.len() as u32;
1481
146k
            if self.response_frame_size >= ilen {
1482
146k
                self.response_frame_size -= ilen;
1483
146k
                return AppLayerResult::ok();
1484
102
            } else {
1485
102
                let start = self.response_frame_size as usize;
1486
102
                input = &input[start..];
1487
102
                self.response_frame_size = 0;
1488
102
            }
1489
1.76M
        }
1490
        //then parse all we can
1491
1.76M
        return self.parse_frames(input, il, Direction::ToClient, flow, &stream_slice);
1492
1.91M
    }
1493
}
1494
1495
// C exports.
1496
1497
#[no_mangle]
1498
0
pub unsafe extern "C" fn SCDoH2GetDnsTx(
1499
0
    tx: &HTTP2Transaction, flags: u8,
1500
0
) -> *mut std::os::raw::c_void {
1501
0
    if let Some(doh) = &tx.doh {
1502
0
        if flags & Direction::ToServer as u8 != 0 {
1503
0
            if let Some(ref dtx) = &doh.dns_request_tx {
1504
0
                return dtx as *const _ as *mut _;
1505
0
            }
1506
0
        } else if flags & Direction::ToClient as u8 != 0 {
1507
0
            if let Some(ref dtx) = &doh.dns_response_tx {
1508
0
                return dtx as *const _ as *mut _;
1509
0
            }
1510
0
        }
1511
0
    }
1512
0
    std::ptr::null_mut()
1513
0
}
1514
1515
export_tx_data_get!(http2_get_tx_data, HTTP2Transaction);
1516
export_state_data_get!(http2_get_state_data, HTTP2State);
1517
1518
/// C entry point for a probing parser.
1519
107
unsafe extern "C" fn http2_probing_parser_tc(
1520
107
    _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8,
1521
107
) -> AppProto {
1522
107
    if !input.is_null() {
1523
107
        let slice = build_slice!(input, input_len as usize);
1524
107
        match parser::http2_parse_frame_header(slice) {
1525
107
            Ok((_, header)) => {
1526
107
                if header.reserved != 0
1527
66
                    || header.length > HTTP2_DEFAULT_MAX_FRAME_SIZE
1528
15
                    || header.flags & 0xFE != 0
1529
5
                    || header.ftype != parser::HTTP2FrameType::Settings as u8
1530
                {
1531
105
                    return ALPROTO_FAILED;
1532
2
                }
1533
2
                return ALPROTO_HTTP2;
1534
            }
1535
            Err(Err::Incomplete(_)) => {
1536
0
                return ALPROTO_UNKNOWN;
1537
            }
1538
            Err(_) => {
1539
0
                return ALPROTO_FAILED;
1540
            }
1541
        }
1542
0
    }
1543
0
    return ALPROTO_UNKNOWN;
1544
107
}
1545
1546
// Extern functions operating on HTTP2.
1547
extern "C" {
1548
    pub fn HTTP2MimicHttp1Request(
1549
        orig_state: *mut std::os::raw::c_void, new_state: *mut std::os::raw::c_void,
1550
    );
1551
}
1552
1553
// Suppress the unsafe warning here as creating a state for an app-layer
1554
// is typically not unsafe.
1555
#[allow(clippy::not_unsafe_ptr_arg_deref)]
1556
14.2k
extern "C" fn http2_state_new(
1557
14.2k
    orig_state: *mut std::os::raw::c_void, orig_proto: AppProto,
1558
14.2k
) -> *mut std::os::raw::c_void {
1559
14.2k
    let state = HTTP2State::new();
1560
14.2k
    let boxed = Box::new(state);
1561
14.2k
    let r = Box::into_raw(boxed) as *mut _;
1562
14.2k
    if !orig_state.is_null() && orig_proto == ALPROTO_HTTP1 as u16 {
1563
0
        unsafe {
1564
0
            HTTP2MimicHttp1Request(orig_state, r);
1565
0
        }
1566
14.2k
    }
1567
14.2k
    return r;
1568
14.2k
}
1569
1570
14.2k
unsafe extern "C" fn http2_state_free(state: *mut std::os::raw::c_void) {
1571
14.2k
    let mut state: Box<HTTP2State> = Box::from_raw(state as _);
1572
14.2k
    state.free();
1573
14.2k
}
1574
1575
2.09M
unsafe extern "C" fn http2_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) {
1576
2.09M
    let state = cast_pointer!(state, HTTP2State);
1577
2.09M
    state.free_tx(tx_id);
1578
2.09M
}
1579
1580
1.92M
unsafe extern "C" fn http2_parse_ts(
1581
1.92M
    flow: *mut Flow, state: *mut std::os::raw::c_void, _pstate: *mut AppLayerParserState,
1582
1.92M
    stream_slice: StreamSlice, _data: *const std::os::raw::c_void,
1583
1.92M
) -> AppLayerResult {
1584
1.92M
    let state = cast_pointer!(state, HTTP2State);
1585
1.92M
    return state.parse_ts(flow, stream_slice);
1586
1.92M
}
1587
1588
1.91M
unsafe extern "C" fn http2_parse_tc(
1589
1.91M
    flow: *mut Flow, state: *mut std::os::raw::c_void, _pstate: *mut AppLayerParserState,
1590
1.91M
    stream_slice: StreamSlice, _data: *const std::os::raw::c_void,
1591
1.91M
) -> AppLayerResult {
1592
1.91M
    let state = cast_pointer!(state, HTTP2State);
1593
1.91M
    return state.parse_tc(flow, stream_slice);
1594
1.91M
}
1595
1596
0
unsafe extern "C" fn http2_state_get_tx(
1597
0
    state: *mut std::os::raw::c_void, tx_id: u64,
1598
0
) -> *mut std::os::raw::c_void {
1599
0
    let state = cast_pointer!(state, HTTP2State);
1600
0
    match state.get_tx(tx_id) {
1601
0
        Some(tx) => {
1602
0
            return tx as *const _ as *mut _;
1603
        }
1604
        None => {
1605
0
            return std::ptr::null_mut();
1606
        }
1607
    }
1608
0
}
1609
1610
11.4M
unsafe extern "C" fn http2_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 {
1611
11.4M
    let state = cast_pointer!(state, HTTP2State);
1612
11.4M
    return state.tx_id;
1613
11.4M
}
1614
1615
67.3M
unsafe extern "C" fn http2_tx_get_state(tx: *mut std::os::raw::c_void) -> HTTP2TransactionState {
1616
67.3M
    let tx = cast_pointer!(tx, HTTP2Transaction);
1617
67.3M
    return tx.state;
1618
67.3M
}
1619
1620
67.3M
unsafe extern "C" fn http2_tx_get_alstate_progress(
1621
67.3M
    tx: *mut std::os::raw::c_void, _direction: u8,
1622
67.3M
) -> std::os::raw::c_int {
1623
67.3M
    return http2_tx_get_state(tx) as i32;
1624
67.3M
}
1625
1626
30.9M
unsafe extern "C" fn http2_getfiles(
1627
30.9M
    tx: *mut std::os::raw::c_void, direction: u8,
1628
30.9M
) -> AppLayerGetFileState {
1629
30.9M
    let tx = cast_pointer!(tx, HTTP2Transaction);
1630
30.9M
    if let Some(sfcm) = { SURICATA_HTTP2_FILE_CONFIG } {
1631
30.9M
        if direction & STREAM_TOSERVER != 0 {
1632
15.4M
            return AppLayerGetFileState {
1633
15.4M
                fc: &mut tx.ft_ts.file,
1634
15.4M
                cfg: sfcm.files_sbcfg,
1635
15.4M
            };
1636
        } else {
1637
15.4M
            return AppLayerGetFileState {
1638
15.4M
                fc: &mut tx.ft_tc.file,
1639
15.4M
                cfg: sfcm.files_sbcfg,
1640
15.4M
            };
1641
        }
1642
0
    }
1643
0
    AppLayerGetFileState::err()
1644
30.9M
}
1645
1646
// Parser name as a C style string.
1647
const PARSER_NAME: &[u8] = b"http2\0";
1648
1649
#[no_mangle]
1650
40
pub unsafe extern "C" fn SCRegisterHttp2Parser() {
1651
40
    let default_port = CString::new("[80]").unwrap();
1652
40
    let mut parser = RustParser {
1653
40
        name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
1654
40
        default_port: default_port.as_ptr(),
1655
40
        ipproto: IPPROTO_TCP,
1656
40
        probe_ts: None, // big magic string should be enough
1657
40
        probe_tc: Some(http2_probing_parser_tc),
1658
40
        min_depth: HTTP2_FRAME_HEADER_LEN as u16,
1659
40
        max_depth: HTTP2_MAGIC_LEN as u16,
1660
40
        state_new: http2_state_new,
1661
40
        state_free: http2_state_free,
1662
40
        tx_free: http2_state_tx_free,
1663
40
        parse_ts: http2_parse_ts,
1664
40
        parse_tc: http2_parse_tc,
1665
40
        get_tx_count: http2_state_get_tx_count,
1666
40
        get_tx: http2_state_get_tx,
1667
40
        tx_comp_st_ts: HTTP2TransactionState::HTTP2StateClosed as i32,
1668
40
        tx_comp_st_tc: HTTP2TransactionState::HTTP2StateClosed as i32,
1669
40
        tx_get_progress: http2_tx_get_alstate_progress,
1670
40
        get_eventinfo: Some(HTTP2Event::get_event_info),
1671
40
        get_eventinfo_byid: Some(HTTP2Event::get_event_info_by_id),
1672
40
        localstorage_new: None,
1673
40
        localstorage_free: None,
1674
40
        get_tx_files: Some(http2_getfiles),
1675
40
        get_tx_iterator: Some(applayer::state_get_tx_iterator::<HTTP2State, HTTP2Transaction>),
1676
40
        get_tx_data: http2_get_tx_data,
1677
40
        get_state_data: http2_get_state_data,
1678
40
        apply_tx_config: None,
1679
40
        flags: 0,
1680
40
        get_frame_id_by_name: Some(Http2FrameType::ffi_id_from_name),
1681
40
        get_frame_name_by_id: Some(Http2FrameType::ffi_name_from_id),
1682
40
        get_state_id_by_name: None,
1683
40
        get_state_name_by_id: None,
1684
40
    };
1685
1686
40
    let ip_proto_str = CString::new("tcp").unwrap();
1687
1688
40
    if SCAppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
1689
40
        let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
1690
40
        ALPROTO_HTTP2 = alproto;
1691
40
        if SCAppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
1692
40
            let _ = AppLayerRegisterParser(&parser, alproto);
1693
40
        }
1694
40
        if let Some(val) = conf_get("app-layer.protocols.http2.max-streams") {
1695
0
            if let Ok(v) = val.parse::<usize>() {
1696
0
                HTTP2_MAX_STREAMS = v;
1697
0
            } else {
1698
0
                SCLogError!("Invalid value for http2.max-streams");
1699
            }
1700
40
        }
1701
40
        if let Some(val) = conf_get("app-layer.protocols.http2.max-frames") {
1702
0
            if let Ok(v) = val.parse::<usize>() {
1703
0
                HTTP2_MAX_FRAMES = v;
1704
0
            } else {
1705
0
                SCLogError!("Invalid value for http2.max-frames");
1706
            }
1707
40
        }
1708
40
        if let Some(val) = conf_get("app-layer.protocols.http2.max-table-size") {
1709
0
            if let Ok(v) = val.parse::<u32>() {
1710
0
                HTTP2_MAX_TABLESIZE = v;
1711
0
            } else {
1712
0
                SCLogError!("Invalid value for http2.max-table-size");
1713
            }
1714
40
        }
1715
40
        if let Some(val) = conf_get("app-layer.protocols.http2.max-reassembly-size") {
1716
0
            if let Ok(v) = val.parse::<u32>() {
1717
0
                HTTP2_MAX_REASS = v as usize;
1718
0
            } else {
1719
0
                SCLogError!("Invalid value for http2.max-reassembly-size");
1720
            }
1721
40
        }
1722
40
        if let Some(val) = conf_get("app-layer.protocols.http2.compression-bomb-limit") {
1723
0
            if let Ok(v) = get_memval(val) {
1724
0
                HTTP2_COMPRESSION_BOMB_LIMIT = v;
1725
0
            } else {
1726
0
                SCLogWarning!("Invalid value for http2.compression-bomb-limit");
1727
            }
1728
40
        }
1729
40
        SCAppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP2);
1730
        SCLogDebug!("Rust http2 parser registered.");
1731
    } else {
1732
0
        SCLogNotice!("Protocol detector and parser disabled for HTTP2.");
1733
    }
1734
1735
    // doh2 is just http2 wrapped in another name
1736
40
    parser.name = b"doh2\0".as_ptr() as *const std::os::raw::c_char;
1737
40
    parser.probe_tc = None;
1738
40
    parser.default_port = std::ptr::null();
1739
40
    if SCAppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
1740
40
        let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
1741
40
        ALPROTO_DOH2 = alproto;
1742
40
        if SCAppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
1743
40
            let _ = AppLayerRegisterParser(&parser, alproto);
1744
40
        } else {
1745
0
            SCLogWarning!("DOH2 is not meant to be detection-only.");
1746
        }
1747
40
        SCAppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DOH2);
1748
        SCLogDebug!("Rust doh2 parser registered.");
1749
    } else {
1750
0
        SCLogNotice!("Protocol detector and parser disabled for DOH2.");
1751
    }
1752
40
}