• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 23180620428

11 Mar 2026 07:26AM UTC coverage: 79.302% (+60.4%) from 18.946%
23180620428

push

github

victorjulien
ldap: add rules file to dist

265910 of 335312 relevant lines covered (79.3%)

5647520.21 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.57
/rust/src/http2/http2.rs
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 super::range::{SCHTPFileCloseHandleRange, SCHttpRangeFreeBlock};
24
use crate::applayer::{self, *};
25
use crate::conf::conf_get;
26
use crate::core::*;
27
use crate::direction::Direction;
28
use crate::dns::dns::DnsVariant;
29
use crate::filecontainer::FileContainerWrapper;
30
use crate::filetracker::*;
31
use crate::flow::Flow;
32
use crate::frames::Frame;
33

34
use crate::dns::dns::{dns_parse_request, dns_parse_response, DNSTransaction};
35

36
use nom7::Err;
37
use std;
38
use std::collections::VecDeque;
39
use std::ffi::CString;
40
use std::fmt;
41
use std::io;
42
use suricata_sys::sys::{
43
    AppLayerParserState, AppProto, HttpRangeContainerBlock, SCAppLayerForceProtocolChange,
44
    SCAppLayerParserConfParserEnabled, SCAppLayerParserRegisterLogger,
45
    SCAppLayerProtoDetectConfProtoDetectionEnabled, SCFileFlowFlagsToFlags,
46
    SCHTTP2MimicHttp1Request,
47
};
48

49
static mut ALPROTO_HTTP2: AppProto = ALPROTO_UNKNOWN;
50
static mut ALPROTO_DOH2: AppProto = ALPROTO_UNKNOWN;
51

52
const HTTP2_DEFAULT_MAX_FRAME_SIZE: u32 = 16384;
53
const HTTP2_MAX_HANDLED_FRAME_SIZE: usize = 65536;
54
const HTTP2_MIN_HANDLED_FRAME_SIZE: usize = 256;
55

56
pub static mut SURICATA_HTTP2_FILE_CONFIG: Option<&'static SuricataFileContext> = None;
57

58
#[no_mangle]
59
pub extern "C" fn SCHttp2Init(context: &'static mut SuricataFileContext) {
2,226✔
60
    unsafe {
2,226✔
61
        SURICATA_HTTP2_FILE_CONFIG = Some(context);
2,226✔
62
    }
2,226✔
63
}
2,226✔
64

65
#[repr(u8)]
66
#[derive(Copy, Clone, PartialOrd, PartialEq, Eq)]
67
pub enum HTTP2ConnectionState {
68
    Http2StateInit = 0,
69
    Http2StateMagicDone = 1,
70
}
71

72
const HTTP2_FRAME_HEADER_LEN: usize = 9;
73
const HTTP2_MAGIC_LEN: usize = 24;
74
const HTTP2_FRAME_GOAWAY_LEN: usize = 8;
75
const HTTP2_FRAME_RSTSTREAM_LEN: usize = 4;
76
const HTTP2_FRAME_PRIORITY_LEN: usize = 5;
77
const HTTP2_FRAME_WINDOWUPDATE_LEN: usize = 4;
78
pub static mut HTTP2_MAX_TABLESIZE: u32 = 65536; // 0x10000
79
                                                 // maximum size of reassembly for header + continuation
80
static mut HTTP2_MAX_REASS: usize = 102400;
81
static mut HTTP2_MAX_STREAMS: usize = 4096; // 0x1000
82
static mut HTTP2_MAX_FRAMES: usize = 65536;
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
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
×
102
        write!(f, "{:?}", self)
×
103
    }
×
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
    fn id(&self) -> u64 {
707,640✔
188
        self.tx_id
707,640✔
189
    }
707,640✔
190
}
191

192
impl Default for HTTP2Transaction {
193
    fn default() -> Self {
×
194
        Self::new()
×
195
    }
×
196
}
197

198
impl HTTP2Transaction {
199
    pub fn new() -> Self {
14,924✔
200
        Self {
14,924✔
201
            tx_id: 0,
14,924✔
202
            stream_id: 0,
14,924✔
203
            child_stream_id: 0,
14,924✔
204
            state: HTTP2TransactionState::HTTP2StateIdle,
14,924✔
205
            frames_tc: Vec::new(),
14,924✔
206
            frames_ts: Vec::new(),
14,924✔
207
            decoder: decompression::HTTP2Decoder::new(),
14,924✔
208
            file_range: std::ptr::null_mut(),
14,924✔
209
            tx_data: AppLayerTxData::new(),
14,924✔
210
            ft_tc: FileTransferTracker::new(),
14,924✔
211
            ft_ts: FileTransferTracker::new(),
14,924✔
212
            req_line: Vec::new(),
14,924✔
213
            resp_line: Vec::new(),
14,924✔
214
            doh: None,
14,924✔
215
        }
14,924✔
216
    }
14,924✔
217

218
    pub fn free(&mut self) {
14,924✔
219
        if !self.file_range.is_null() {
14,924✔
220
            if let Some(sfcm) = unsafe { SURICATA_HTTP2_FILE_CONFIG } {
×
221
                //TODO get a file container instead of NULL
×
222
                unsafe {
×
223
                    SCHTPFileCloseHandleRange(
×
224
                        sfcm.files_sbcfg,
×
225
                        std::ptr::null_mut(),
×
226
                        0,
×
227
                        self.file_range,
×
228
                        std::ptr::null_mut(),
×
229
                        0,
×
230
                    );
×
231
                    SCHttpRangeFreeBlock(self.file_range);
×
232
                }
×
233
                self.file_range = std::ptr::null_mut();
×
234
            }
×
235
        }
14,924✔
236
    }
14,924✔
237

238
    pub fn set_event(&mut self, event: HTTP2Event) {
30✔
239
        self.tx_data.set_event(event as u8);
30✔
240
    }
30✔
241

242
    fn handle_headers(
5,009✔
243
        &mut self, blocks: &[parser::HTTP2FrameHeaderBlock], dir: Direction,
5,009✔
244
    ) -> Option<Vec<u8>> {
5,009✔
245
        let mut authority = None;
5,009✔
246
        let mut path = None;
5,009✔
247
        let mut doh = false;
5,009✔
248
        let mut host = None;
5,009✔
249
        for block in blocks {
70,384✔
250
            if block.name.as_ref() == b"content-encoding" {
65,375✔
251
                self.decoder.http2_encoding_fromvec(&block.value, dir);
241✔
252
            } else if block.name.as_ref() == b"accept" {
65,134✔
253
                //TODO? faster pattern matching
254
                if block.value.as_ref() == b"application/dns-message" {
2,415✔
255
                    doh = true;
1,863✔
256
                }
1,879✔
257
            } else if block.name.as_ref() == b"content-type" {
62,719✔
258
                if block.value.as_ref() == b"application/dns-message" {
3,910✔
259
                    if let Some(doh) = &mut self.doh {
3,296✔
260
                        doh.is_doh_data[dir.index()] = true;
1,323✔
261
                    } else {
1,979✔
262
                        let mut doh = DohHttp2Tx::default();
1,973✔
263
                        doh.is_doh_data[dir.index()] = true;
1,973✔
264
                        self.doh = Some(doh);
1,973✔
265
                    }
1,973✔
266
                }
614✔
267
            } else if block.name.as_ref() == b":path" {
58,809✔
268
                path = Some(&block.value);
2,699✔
269
            } else if block.name.eq_ignore_ascii_case(b":authority") {
56,110✔
270
                authority = Some(&block.value);
2,556✔
271
                if block.value.contains(&b'@') {
2,556✔
272
                    // it is forbidden by RFC 9113 to have userinfo in this field
12✔
273
                    // when in HTTP1 we can have user:password@domain.com
12✔
274
                    self.set_event(HTTP2Event::UserinfoInUri);
12✔
275
                }
2,544✔
276
            } else if block.name.eq_ignore_ascii_case(b"host") {
53,554✔
277
                host = Some(&block.value);
13✔
278
            }
53,541✔
279
        }
280
        if let Some(a) = authority {
5,009✔
281
            if let Some(h) = host {
2,497✔
282
                if !a.eq_ignore_ascii_case(h) {
11✔
283
                    // The event is triggered only if both headers
11✔
284
                    // are in the same frame to avoid excessive
11✔
285
                    // complexity at runtime.
11✔
286
                    self.set_event(HTTP2Event::AuthorityHostMismatch);
11✔
287
                }
11✔
288
            }
2,486✔
289
        }
2,512✔
290
        if doh && unsafe { ALPROTO_DOH2 } != ALPROTO_UNKNOWN {
5,009✔
291
            if let Some(p) = path {
1,863✔
292
                if let Ok((_, dns_req)) = parser::doh_extract_request(p) {
1,861✔
293
                    return Some(dns_req);
175✔
294
                }
1,686✔
295
            }
2✔
296
        }
3,146✔
297
        return None;
4,834✔
298
    }
5,009✔
299

300
    pub fn update_file_flags(&mut self, flow_file_flags: u16) {
26,642✔
301
        self.ft_ts.file_flags = unsafe { SCFileFlowFlagsToFlags(flow_file_flags, STREAM_TOSERVER) };
26,642✔
302
        self.ft_tc.file_flags = unsafe { SCFileFlowFlagsToFlags(flow_file_flags, STREAM_TOCLIENT) };
26,642✔
303
    }
26,642✔
304

305
    fn decompress<'a>(
8,039✔
306
        &'a mut self, input: &'a [u8], output: &'a mut Vec<u8>, dir: Direction,
8,039✔
307
        sfcm: &'static SuricataFileContext, over: bool, flow: *const Flow,
8,039✔
308
    ) -> io::Result<()> {
8,039✔
309
        let decompressed = self.decoder.decompress(input, output, dir)?;
8,039✔
310
        let xid: u32 = self.tx_id as u32;
7,976✔
311
        if dir == Direction::ToClient {
7,976✔
312
            self.ft_tc.tx_id = self.tx_id - 1;
5,775✔
313
            // Check that we are at the beginning of the file
5,775✔
314
            if !self.ft_tc.is_initialized() {
5,775✔
315
                // we are now sure that new_chunk will open a file
316
                // even if it may close it right afterwards
317
                self.tx_data.incr_files_opened();
2,426✔
318
                if let Ok(value) = detect::http2_frames_get_header_value_vec(
2,426✔
319
                    self,
2,426✔
320
                    Direction::ToClient,
2,426✔
321
                    "content-range",
2,426✔
322
                ) {
2,426✔
323
                    match range::http2_parse_check_content_range(&value) {
79✔
324
                        Ok((_, v)) => {
75✔
325
                            range::http2_range_open(
75✔
326
                                self,
75✔
327
                                &v,
75✔
328
                                flow,
75✔
329
                                sfcm,
75✔
330
                                Direction::ToClient,
75✔
331
                                decompressed,
75✔
332
                            );
75✔
333
                            if over && !self.file_range.is_null() {
75✔
334
                                range::http2_range_close(self, Direction::ToClient, &[])
71✔
335
                            }
4✔
336
                        }
337
                        _ => {
4✔
338
                            self.set_event(HTTP2Event::InvalidRange);
4✔
339
                        }
4✔
340
                    }
341
                }
2,347✔
342
            } else if !self.file_range.is_null() {
3,349✔
343
                if over {
×
344
                    range::http2_range_close(self, Direction::ToClient, decompressed)
×
345
                } else {
346
                    range::http2_range_append(sfcm, self.file_range, decompressed)
×
347
                }
348
            }
3,349✔
349
            self.ft_tc.new_chunk(
5,775✔
350
                sfcm,
5,775✔
351
                b"",
5,775✔
352
                decompressed,
5,775✔
353
                self.ft_tc.tracked, //offset = append
5,775✔
354
                decompressed.len() as u32,
5,775✔
355
                0,
5,775✔
356
                over,
5,775✔
357
                &xid,
5,775✔
358
            );
5,775✔
359
        } else {
360
            self.ft_ts.tx_id = self.tx_id - 1;
2,201✔
361
            if !self.ft_ts.file_open {
2,201✔
362
                self.tx_data.incr_files_opened();
2,159✔
363
            }
2,159✔
364
            self.ft_ts.new_chunk(
2,201✔
365
                sfcm,
2,201✔
366
                b"",
2,201✔
367
                decompressed,
2,201✔
368
                self.ft_ts.tracked, //offset = append
2,201✔
369
                decompressed.len() as u32,
2,201✔
370
                0,
2,201✔
371
                over,
2,201✔
372
                &xid,
2,201✔
373
            );
2,201✔
374
        };
375
        if unsafe { ALPROTO_DOH2 } != ALPROTO_UNKNOWN {
7,976✔
376
            // we store DNS response, and process it when complete
377
            if let Some(doh) = &mut self.doh {
7,976✔
378
                if doh.is_doh_data[dir.index()] {
5,167✔
379
                    if doh.data_buf[dir.index()].len() + decompressed.len() <= 0xFFFF {
4,866✔
380
                        // a DNS message is U16_MAX
4,863✔
381
                        doh.data_buf[dir.index()].extend_from_slice(decompressed);
4,863✔
382
                    } else {
4,863✔
383
                        // stop processing further data
384
                        doh.is_doh_data[dir.index()] = false;
3✔
385
                        if dir == Direction::ToClient {
3✔
386
                            self.set_event(HTTP2Event::DnsResponseTooLong);
×
387
                        } else {
3✔
388
                            self.set_event(HTTP2Event::DnsRequestTooLong);
3✔
389
                        }
3✔
390
                    }
391
                }
301✔
392
            }
2,809✔
393
        }
×
394
        return Ok(());
7,976✔
395
    }
8,039✔
396

397
    fn handle_frame(
24,687✔
398
        &mut self, header: &parser::HTTP2FrameHeader, data: &HTTP2FrameTypeData, dir: Direction,
24,687✔
399
    ) -> Option<Vec<u8>> {
24,687✔
400
        //handle child_stream_id changes
24,687✔
401
        let mut r = None;
24,687✔
402
        match data {
24,687✔
403
            HTTP2FrameTypeData::PUSHPROMISE(hs) => {
4✔
404
                if dir == Direction::ToClient {
4✔
405
                    //we could set an event if self.child_stream_id != 0
406
                    if header.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS == 0 {
×
407
                        self.child_stream_id = hs.stream_id;
×
408
                    }
×
409
                    self.state = HTTP2TransactionState::HTTP2StateReserved;
×
410
                }
4✔
411
                r = self.handle_headers(&hs.blocks, dir);
4✔
412
            }
413
            HTTP2FrameTypeData::CONTINUATION(hs) => {
21✔
414
                if dir == Direction::ToClient
21✔
415
                    && header.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS != 0
5✔
416
                {
4✔
417
                    self.child_stream_id = 0;
4✔
418
                }
17✔
419
                r = self.handle_headers(&hs.blocks, dir);
21✔
420
            }
421
            HTTP2FrameTypeData::HEADERS(hs) => {
4,984✔
422
                if dir == Direction::ToClient {
4,984✔
423
                    self.child_stream_id = 0;
2,349✔
424
                }
2,658✔
425
                r = self.handle_headers(&hs.blocks, dir);
4,984✔
426
            }
427
            HTTP2FrameTypeData::RSTSTREAM(_) => {
123✔
428
                self.child_stream_id = 0;
123✔
429
            }
123✔
430
            _ => {}
19,555✔
431
        }
432
        //handle closing state changes
433
        match data {
24,687✔
434
            HTTP2FrameTypeData::HEADERS(_) | HTTP2FrameTypeData::DATA => {
435
                if header.flags & parser::HTTP2_FLAG_HEADER_EOS != 0 {
17,863✔
436
                    match self.state {
5,006✔
437
                        HTTP2TransactionState::HTTP2StateHalfClosedClient
438
                        | HTTP2TransactionState::HTTP2StateDataServer => {
439
                            if dir == Direction::ToClient {
2,238✔
440
                                self.state = HTTP2TransactionState::HTTP2StateClosed;
2,233✔
441
                            }
2,233✔
442
                        }
443
                        HTTP2TransactionState::HTTP2StateHalfClosedServer => {
444
                            if dir == Direction::ToServer {
3✔
445
                                self.state = HTTP2TransactionState::HTTP2StateClosed;
1✔
446
                            }
2✔
447
                        }
448
                        // do not revert back to a half closed state
449
                        HTTP2TransactionState::HTTP2StateClosed => {}
5✔
450
                        HTTP2TransactionState::HTTP2StateGlobal => {}
19✔
451
                        _ => {
452
                            if dir == Direction::ToClient {
2,741✔
453
                                self.state = HTTP2TransactionState::HTTP2StateHalfClosedServer;
59✔
454
                            } else {
2,682✔
455
                                self.state = HTTP2TransactionState::HTTP2StateHalfClosedClient;
2,682✔
456
                            }
2,682✔
457
                        }
458
                    }
459
                } else if header.ftype == parser::HTTP2FrameType::Data as u8 {
12,857✔
460
                    //not end of stream
461
                    if dir == Direction::ToServer {
8,582✔
462
                        if self.state < HTTP2TransactionState::HTTP2StateDataClient {
685✔
463
                            self.state = HTTP2TransactionState::HTTP2StateDataClient;
159✔
464
                        }
526✔
465
                    } else if self.state < HTTP2TransactionState::HTTP2StateDataServer {
7,897✔
466
                        self.state = HTTP2TransactionState::HTTP2StateDataServer;
2,186✔
467
                    }
5,711✔
468
                }
4,275✔
469
            }
470
            _ => {}
6,824✔
471
        }
472
        return r;
24,687✔
473
    }
24,687✔
474

475
    fn handle_dns_data(&mut self, dir: Direction, flow: *mut Flow) {
4,249✔
476
        if let Some(doh) = &mut self.doh {
4,249✔
477
            if !doh.data_buf[dir.index()].is_empty() {
3,330✔
478
                if dir.is_to_client() {
3,185✔
479
                    if let Ok(mut dtx) = dns_parse_response(&doh.data_buf[dir.index()]) {
1,599✔
480
                        dtx.id = 1;
1,561✔
481
                        doh.dns_response_tx = Some(dtx);
1,561✔
482
                        unsafe {
1,561✔
483
                            SCAppLayerForceProtocolChange(flow, ALPROTO_DOH2);
1,561✔
484
                        }
1,561✔
485
                    }
38✔
486
                } else if let Ok(mut dtx) =
1,563✔
487
                    dns_parse_request(&doh.data_buf[dir.index()], &DnsVariant::Dns)
1,586✔
488
                {
489
                    dtx.id = 1;
1,563✔
490
                    doh.dns_request_tx = Some(dtx);
1,563✔
491
                    unsafe {
1,563✔
492
                        SCAppLayerForceProtocolChange(flow, ALPROTO_DOH2);
1,563✔
493
                    }
1,563✔
494
                }
23✔
495
            }
145✔
496
        }
919✔
497
    }
4,249✔
498
}
499

500
impl Drop for HTTP2Transaction {
501
    fn drop(&mut self) {
14,924✔
502
        if let Some(sfcm) = unsafe { SURICATA_HTTP2_FILE_CONFIG } {
14,924✔
503
            self.ft_ts.file.free(sfcm);
14,923✔
504
            self.ft_tc.file.free(sfcm);
14,923✔
505
        }
14,924✔
506
        self.free();
14,924✔
507
    }
14,924✔
508
}
509

510
#[derive(AppLayerEvent)]
13,834✔
511
pub enum HTTP2Event {
512
    InvalidFrameHeader,
513
    InvalidClientMagic,
514
    InvalidFrameData,
515
    InvalidHeader,
516
    InvalidFrameLength,
517
    ExtraHeaderData,
518
    LongFrameData,
519
    StreamIdReuse,
520
    InvalidHttp1Settings,
521
    FailedDecompression,
522
    InvalidRange,
523
    HeaderIntegerOverflow,
524
    TooManyStreams,
525
    AuthorityHostMismatch,
526
    UserinfoInUri,
527
    ReassemblyLimitReached,
528
    DnsRequestTooLong,
529
    DnsResponseTooLong,
530
    DataStreamZero,
531
    TooManyFrames,
532
}
533

534
pub struct HTTP2DynTable {
535
    pub table: Vec<parser::HTTP2FrameHeaderBlock>,
536
    pub current_size: usize,
537
    pub max_size: usize,
538
    pub overflow: u8,
539
}
540

541
impl Default for HTTP2DynTable {
542
    fn default() -> Self {
×
543
        Self::new()
×
544
    }
×
545
}
546

547
impl HTTP2DynTable {
548
    pub fn new() -> Self {
2,419✔
549
        Self {
2,419✔
550
            table: Vec::with_capacity(64),
2,419✔
551
            current_size: 0,
2,419✔
552
            max_size: 4096, //default value
2,419✔
553
            overflow: 0,
2,419✔
554
        }
2,419✔
555
    }
2,419✔
556
}
557

558
#[derive(Default)]
559
struct HTTP2HeaderReassemblyBuffer {
560
    data: Vec<u8>,
561
    stream_id: u32,
562
}
563

564
pub struct HTTP2State {
565
    state_data: AppLayerStateData,
566
    tx_id: u64,
567
    request_frame_size: u32,
568
    response_frame_size: u32,
569
    dynamic_headers_ts: HTTP2DynTable,
570
    dynamic_headers_tc: HTTP2DynTable,
571
    transactions: VecDeque<HTTP2Transaction>,
572
    progress: HTTP2ConnectionState,
573

574
    c2s_buf: HTTP2HeaderReassemblyBuffer,
575
    s2c_buf: HTTP2HeaderReassemblyBuffer,
576
}
577

578
impl State<HTTP2Transaction> for HTTP2State {
579
    fn get_transaction_count(&self) -> usize {
258,779✔
580
        self.transactions.len()
258,779✔
581
    }
258,779✔
582

583
    fn get_transaction_by_index(&self, index: usize) -> Option<&HTTP2Transaction> {
449,966✔
584
        self.transactions.get(index)
449,966✔
585
    }
449,966✔
586
}
587

588
impl Default for HTTP2State {
589
    fn default() -> Self {
×
590
        Self::new()
×
591
    }
×
592
}
593

594
impl HTTP2State {
595
    pub fn new() -> Self {
1,209✔
596
        Self {
1,209✔
597
            state_data: AppLayerStateData::default(),
1,209✔
598
            tx_id: 0,
1,209✔
599
            request_frame_size: 0,
1,209✔
600
            response_frame_size: 0,
1,209✔
601
            // the headers are encoded on one byte
1,209✔
602
            // with a fixed number of static headers, and
1,209✔
603
            // a variable number of dynamic headers
1,209✔
604
            dynamic_headers_ts: HTTP2DynTable::new(),
1,209✔
605
            dynamic_headers_tc: HTTP2DynTable::new(),
1,209✔
606
            transactions: VecDeque::new(),
1,209✔
607
            progress: HTTP2ConnectionState::Http2StateInit,
1,209✔
608
            c2s_buf: HTTP2HeaderReassemblyBuffer::default(),
1,209✔
609
            s2c_buf: HTTP2HeaderReassemblyBuffer::default(),
1,209✔
610
        }
1,209✔
611
    }
1,209✔
612

613
    pub fn free(&mut self) {
1,209✔
614
        // this should be in HTTP2Transaction::free
615
        // but we need state's file container cf https://redmine.openinfosecfoundation.org/issues/4444
616
        for tx in &mut self.transactions {
6,502✔
617
            if !tx.file_range.is_null() {
5,293✔
618
                if let Some(sfcm) = unsafe { SURICATA_HTTP2_FILE_CONFIG } {
×
619
                    unsafe {
×
620
                        SCHTPFileCloseHandleRange(
×
621
                            sfcm.files_sbcfg,
×
622
                            &mut tx.ft_tc.file,
×
623
                            0,
×
624
                            tx.file_range,
×
625
                            std::ptr::null_mut(),
×
626
                            0,
×
627
                        );
×
628
                        SCHttpRangeFreeBlock(tx.file_range);
×
629
                    }
×
630
                    tx.file_range = std::ptr::null_mut();
×
631
                }
×
632
            }
5,293✔
633
        }
634
        self.transactions.clear();
1,209✔
635
    }
1,209✔
636

637
    pub fn set_event(&mut self, event: HTTP2Event) {
6,833✔
638
        let len = self.transactions.len();
6,833✔
639
        if len == 0 {
6,833✔
640
            return;
108✔
641
        }
6,725✔
642
        let tx = &mut self.transactions[len - 1];
6,725✔
643
        tx.tx_data.set_event(event as u8);
6,725✔
644
    }
6,833✔
645

646
    // Free a transaction by ID.
647
    fn free_tx(&mut self, tx_id: u64) {
9,630✔
648
        let len = self.transactions.len();
9,630✔
649
        let mut found = false;
9,630✔
650
        let mut index = 0;
9,630✔
651
        for i in 0..len {
42,807✔
652
            let tx = &mut self.transactions[i];
42,807✔
653
            if tx.tx_id == tx_id + 1 {
42,807✔
654
                found = true;
9,630✔
655
                index = i;
9,630✔
656
                // this should be in HTTP2Transaction::free
9,630✔
657
                // but we need state's file container cf https://redmine.openinfosecfoundation.org/issues/4444
9,630✔
658
                if !tx.file_range.is_null() {
9,630✔
659
                    if let Some(sfcm) = unsafe { SURICATA_HTTP2_FILE_CONFIG } {
×
660
                        unsafe {
×
661
                            SCHTPFileCloseHandleRange(
×
662
                                sfcm.files_sbcfg,
×
663
                                &mut tx.ft_tc.file,
×
664
                                0,
×
665
                                tx.file_range,
×
666
                                std::ptr::null_mut(),
×
667
                                0,
×
668
                            );
×
669
                            SCHttpRangeFreeBlock(tx.file_range);
×
670
                        }
×
671
                        tx.file_range = std::ptr::null_mut();
×
672
                    }
×
673
                }
9,630✔
674
                break;
9,630✔
675
            }
33,177✔
676
        }
677
        if found {
9,630✔
678
            self.transactions.remove(index);
9,630✔
679
        }
9,630✔
680
    }
9,630✔
681

682
    pub fn get_tx(&mut self, tx_id: u64) -> Option<&HTTP2Transaction> {
9,120✔
683
        for tx in &mut self.transactions {
46,977✔
684
            if tx.tx_id == tx_id + 1 {
46,977✔
685
                tx.tx_data.update_file_flags(self.state_data.file_flags);
9,120✔
686
                tx.update_file_flags(tx.tx_data.0.file_flags);
9,120✔
687
                return Some(tx);
9,120✔
688
            }
37,857✔
689
        }
690
        return None;
×
691
    }
9,120✔
692

693
    fn find_tx_index(&mut self, sid: u32) -> usize {
25,561✔
694
        for i in 0..self.transactions.len() {
70,244✔
695
            //reverse order should be faster
696
            let idx = self.transactions.len() - 1 - i;
70,244✔
697
            if sid == self.transactions[idx].stream_id {
70,244✔
698
                return idx + 1;
19,787✔
699
            }
50,457✔
700
        }
701
        return 0;
5,774✔
702
    }
25,561✔
703

704
    fn find_child_stream_id(&mut self, sid: u32) -> u32 {
4✔
705
        for i in 0..self.transactions.len() {
4✔
706
            //reverse order should be faster
707
            if sid == self.transactions[self.transactions.len() - 1 - i].stream_id {
4✔
708
                if self.transactions[self.transactions.len() - 1 - i].child_stream_id > 0 {
2✔
709
                    return self.transactions[self.transactions.len() - 1 - i].child_stream_id;
×
710
                }
2✔
711
                return sid;
2✔
712
            }
2✔
713
        }
714
        return sid;
2✔
715
    }
4✔
716

717
    fn create_global_tx(&mut self) -> &mut HTTP2Transaction {
9,149✔
718
        //special transaction with only one frame
9,149✔
719
        //as it affects the global connection, there is no end to it
9,149✔
720
        let mut tx = HTTP2Transaction::new();
9,149✔
721
        self.tx_id += 1;
9,149✔
722
        tx.tx_id = self.tx_id;
9,149✔
723
        tx.state = HTTP2TransactionState::HTTP2StateGlobal;
9,149✔
724
        // a global tx (stream id 0) does not hold files cf RFC 9113 section 5.1.1
9,149✔
725
        self.transactions.push_back(tx);
9,149✔
726
        return self.transactions.back_mut().unwrap();
9,149✔
727
    }
9,149✔
728

729
    pub fn find_or_create_tx(
26,671✔
730
        &mut self, header: &parser::HTTP2FrameHeader, data: &HTTP2FrameTypeData, dir: Direction,
26,671✔
731
    ) -> Option<&mut HTTP2Transaction> {
26,671✔
732
        if header.stream_id == 0 {
26,671✔
733
            if self.transactions.len() >= unsafe { HTTP2_MAX_STREAMS } {
9,149✔
734
                for tx_old in &mut self.transactions {
×
735
                    if tx_old.state == HTTP2TransactionState::HTTP2StateTodrop {
×
736
                        // loop was already run
737
                        break;
×
738
                    }
×
739
                    tx_old.set_event(HTTP2Event::TooManyStreams);
×
740
                    // use a distinct state, even if we do not log it
×
741
                    tx_old.state = HTTP2TransactionState::HTTP2StateTodrop;
×
742
                    tx_old.tx_data.0.updated_tc = true;
×
743
                    tx_old.tx_data.0.updated_ts = true;
×
744
                }
745
                return None;
×
746
            }
9,149✔
747
            return Some(self.create_global_tx());
9,149✔
748
        }
17,522✔
749
        let sid = match data {
17,522✔
750
            //yes, the right stream_id for Suricata is not the header one
751
            HTTP2FrameTypeData::PUSHPROMISE(hs) => hs.stream_id,
3✔
752
            HTTP2FrameTypeData::CONTINUATION(_) => {
753
                if dir == Direction::ToClient {
20✔
754
                    //continuation of a push promise
755
                    self.find_child_stream_id(header.stream_id)
4✔
756
                } else {
757
                    header.stream_id
16✔
758
                }
759
            }
760
            _ => header.stream_id,
17,499✔
761
        };
762
        let index = self.find_tx_index(sid);
17,522✔
763
        if index > 0 {
17,522✔
764
            if self.transactions[index - 1].state == HTTP2TransactionState::HTTP2StateClosed {
11,748✔
765
                //these frames can be received in this state for a short period
766
                if header.ftype != parser::HTTP2FrameType::RstStream as u8
99✔
767
                    && header.ftype != parser::HTTP2FrameType::WindowUpdate as u8
19✔
768
                    && header.ftype != parser::HTTP2FrameType::Priority as u8
11✔
769
                {
11✔
770
                    self.set_event(HTTP2Event::StreamIdReuse);
11✔
771
                }
88✔
772
            }
11,649✔
773

774
            let tx = &mut self.transactions[index - 1];
11,748✔
775
            tx.tx_data.update_file_flags(self.state_data.file_flags);
11,748✔
776
            tx.update_file_flags(tx.tx_data.0.file_flags);
11,748✔
777
            tx.tx_data.0.updated_tc = true;
11,748✔
778
            tx.tx_data.0.updated_ts = true;
11,748✔
779
            return Some(tx);
11,748✔
780
        } else {
781
            // do not use SETTINGS_MAX_CONCURRENT_STREAMS as it can grow too much
782
            if self.transactions.len() >= unsafe { HTTP2_MAX_STREAMS } {
5,774✔
783
                for tx_old in &mut self.transactions {
×
784
                    if tx_old.state == HTTP2TransactionState::HTTP2StateTodrop {
×
785
                        // loop was already run
786
                        break;
×
787
                    }
×
788
                    tx_old.set_event(HTTP2Event::TooManyStreams);
×
789
                    // use a distinct state, even if we do not log it
×
790
                    tx_old.state = HTTP2TransactionState::HTTP2StateTodrop;
×
791
                    tx_old.tx_data.0.updated_tc = true;
×
792
                    tx_old.tx_data.0.updated_ts = true;
×
793
                }
794
                return None;
×
795
            }
5,774✔
796
            let mut tx = HTTP2Transaction::new();
5,774✔
797
            self.tx_id += 1;
5,774✔
798
            tx.tx_id = self.tx_id;
5,774✔
799
            tx.stream_id = sid;
5,774✔
800
            tx.state = HTTP2TransactionState::HTTP2StateOpen;
5,774✔
801
            tx.tx_data.update_file_flags(self.state_data.file_flags);
5,774✔
802
            tx.update_file_flags(tx.tx_data.0.file_flags);
5,774✔
803
            tx.tx_data.0.file_tx = STREAM_TOSERVER | STREAM_TOCLIENT; // might hold files in both directions
5,774✔
804
            self.transactions.push_back(tx);
5,774✔
805
            return Some(self.transactions.back_mut().unwrap());
5,774✔
806
        }
807
    }
26,671✔
808

809
    fn process_headers(&mut self, blocks: &Vec<parser::HTTP2FrameHeaderBlock>, dir: Direction) {
4,957✔
810
        let (mut update, mut sizeup) = (false, 0);
4,957✔
811
        for block in blocks {
70,332✔
812
            if block.error >= parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeError {
65,375✔
813
                self.set_event(HTTP2Event::InvalidHeader);
6,134✔
814
            } else if block.error == parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate {
59,241✔
815
                update = true;
945✔
816
                if block.sizeupdate > sizeup {
945✔
817
                    sizeup = block.sizeupdate;
540✔
818
                }
540✔
819
            } else if block.error
58,296✔
820
                == parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeIntegerOverflow
58,296✔
821
            {
×
822
                self.set_event(HTTP2Event::HeaderIntegerOverflow);
×
823
            }
58,296✔
824
        }
825
        if update {
4,957✔
826
            //borrow checker forbids to pass directly dyn_headers
827
            let dyn_headers = if dir == Direction::ToClient {
470✔
828
                &mut self.dynamic_headers_tc
372✔
829
            } else {
830
                &mut self.dynamic_headers_ts
98✔
831
            };
832
            dyn_headers.max_size = sizeup as usize;
470✔
833
        }
4,487✔
834
    }
4,957✔
835

836
    fn parse_frame_data(
24,687✔
837
        &mut self, head: &parser::HTTP2FrameHeader, input: &[u8], complete: bool, dir: Direction,
24,687✔
838
        reass_limit_reached: &mut bool,
24,687✔
839
    ) -> HTTP2FrameTypeData {
24,687✔
840
        let ftype = head.ftype;
24,687✔
841
        let hflags = head.flags;
24,687✔
842
        match num::FromPrimitive::from_u8(ftype) {
24,687✔
843
            Some(parser::HTTP2FrameType::GoAway) => {
844
                if input.len() < HTTP2_FRAME_GOAWAY_LEN {
34✔
845
                    self.set_event(HTTP2Event::InvalidFrameLength);
6✔
846
                    return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
6✔
847
                        reason: HTTP2FrameUnhandledReason::Incomplete,
6✔
848
                    });
6✔
849
                }
28✔
850
                match parser::http2_parse_frame_goaway(input) {
28✔
851
                    Ok((_, goaway)) => {
28✔
852
                        return HTTP2FrameTypeData::GOAWAY(goaway);
28✔
853
                    }
854
                    Err(_) => {
855
                        self.set_event(HTTP2Event::InvalidFrameData);
×
856
                        return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
×
857
                            reason: HTTP2FrameUnhandledReason::ParsingError,
×
858
                        });
×
859
                    }
860
                }
861
            }
862
            Some(parser::HTTP2FrameType::Settings) => {
863
                match parser::http2_parse_frame_settings(input) {
1,970✔
864
                    Ok((_, set)) => {
1,970✔
865
                        for e in &set {
8,305✔
866
                            if e.id == parser::HTTP2SettingsId::HeaderTableSize {
6,335✔
867
                                //reverse order as this is what we accept from the other endpoint
868
                                let dyn_headers = if dir == Direction::ToClient {
955✔
869
                                    &mut self.dynamic_headers_ts
140✔
870
                                } else {
871
                                    &mut self.dynamic_headers_tc
815✔
872
                                };
873
                                dyn_headers.max_size = e.value as usize;
955✔
874
                                if e.value > unsafe { HTTP2_MAX_TABLESIZE } {
955✔
875
                                    //mark potential overflow
23✔
876
                                    dyn_headers.overflow = 1;
23✔
877
                                } else {
932✔
878
                                    //reset in case peer set a lower value, to be tested
932✔
879
                                    dyn_headers.overflow = 0;
932✔
880
                                }
932✔
881
                            }
5,380✔
882
                        }
883
                        //we could set an event on remaining data
884
                        return HTTP2FrameTypeData::SETTINGS(set);
1,970✔
885
                    }
886
                    Err(Err::Incomplete(_)) => {
887
                        if complete {
×
888
                            self.set_event(HTTP2Event::InvalidFrameData);
×
889
                            return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
×
890
                                reason: HTTP2FrameUnhandledReason::ParsingError,
×
891
                            });
×
892
                        } else {
893
                            return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
×
894
                                reason: HTTP2FrameUnhandledReason::TooLong,
×
895
                            });
×
896
                        }
897
                    }
898
                    Err(_) => {
899
                        self.set_event(HTTP2Event::InvalidFrameData);
×
900
                        return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
×
901
                            reason: HTTP2FrameUnhandledReason::ParsingError,
×
902
                        });
×
903
                    }
904
                }
905
            }
906
            Some(parser::HTTP2FrameType::RstStream) => {
907
                if input.len() != HTTP2_FRAME_RSTSTREAM_LEN {
134✔
908
                    self.set_event(HTTP2Event::InvalidFrameLength);
11✔
909
                    return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
11✔
910
                        reason: HTTP2FrameUnhandledReason::Incomplete,
11✔
911
                    });
11✔
912
                } else {
913
                    match parser::http2_parse_frame_rststream(input) {
123✔
914
                        Ok((_, rst)) => {
123✔
915
                            return HTTP2FrameTypeData::RSTSTREAM(rst);
123✔
916
                        }
917
                        Err(_) => {
918
                            self.set_event(HTTP2Event::InvalidFrameData);
×
919
                            return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
×
920
                                reason: HTTP2FrameUnhandledReason::ParsingError,
×
921
                            });
×
922
                        }
923
                    }
924
                }
925
            }
926
            Some(parser::HTTP2FrameType::Priority) => {
927
                if input.len() != HTTP2_FRAME_PRIORITY_LEN {
1,915✔
928
                    self.set_event(HTTP2Event::InvalidFrameLength);
13✔
929
                    return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
13✔
930
                        reason: HTTP2FrameUnhandledReason::Incomplete,
13✔
931
                    });
13✔
932
                } else {
933
                    match parser::http2_parse_frame_priority(input) {
1,902✔
934
                        Ok((_, priority)) => {
1,902✔
935
                            return HTTP2FrameTypeData::PRIORITY(priority);
1,902✔
936
                        }
937
                        Err(_) => {
938
                            self.set_event(HTTP2Event::InvalidFrameData);
×
939
                            return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
×
940
                                reason: HTTP2FrameUnhandledReason::ParsingError,
×
941
                            });
×
942
                        }
943
                    }
944
                }
945
            }
946
            Some(parser::HTTP2FrameType::WindowUpdate) => {
947
                if input.len() != HTTP2_FRAME_WINDOWUPDATE_LEN {
1,886✔
948
                    self.set_event(HTTP2Event::InvalidFrameLength);
11✔
949
                    return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
11✔
950
                        reason: HTTP2FrameUnhandledReason::Incomplete,
11✔
951
                    });
11✔
952
                } else {
953
                    match parser::http2_parse_frame_windowupdate(input) {
1,875✔
954
                        Ok((_, wu)) => {
1,875✔
955
                            return HTTP2FrameTypeData::WINDOWUPDATE(wu);
1,875✔
956
                        }
957
                        Err(_) => {
958
                            self.set_event(HTTP2Event::InvalidFrameData);
×
959
                            return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
×
960
                                reason: HTTP2FrameUnhandledReason::ParsingError,
×
961
                            });
×
962
                        }
963
                    }
964
                }
965
            }
966
            Some(parser::HTTP2FrameType::PushPromise) => {
967
                let dyn_headers = if dir == Direction::ToClient {
34✔
968
                    &mut self.dynamic_headers_tc
3✔
969
                } else {
970
                    &mut self.dynamic_headers_ts
31✔
971
                };
972
                match parser::http2_parse_frame_push_promise(input, hflags, dyn_headers) {
34✔
973
                    Ok((_, hs)) => {
4✔
974
                        self.process_headers(&hs.blocks, dir);
4✔
975
                        return HTTP2FrameTypeData::PUSHPROMISE(hs);
4✔
976
                    }
977
                    Err(Err::Incomplete(_)) => {
978
                        if complete {
30✔
979
                            self.set_event(HTTP2Event::InvalidFrameData);
20✔
980
                            return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
20✔
981
                                reason: HTTP2FrameUnhandledReason::ParsingError,
20✔
982
                            });
20✔
983
                        } else {
984
                            return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
10✔
985
                                reason: HTTP2FrameUnhandledReason::TooLong,
10✔
986
                            });
10✔
987
                        }
988
                    }
989
                    Err(_) => {
990
                        self.set_event(HTTP2Event::InvalidFrameData);
×
991
                        return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
×
992
                            reason: HTTP2FrameUnhandledReason::ParsingError,
×
993
                        });
×
994
                    }
995
                }
996
            }
997
            Some(parser::HTTP2FrameType::Data) => {
998
                return HTTP2FrameTypeData::DATA;
12,879✔
999
            }
1000
            Some(parser::HTTP2FrameType::Continuation) => {
1001
                let buf = if dir == Direction::ToClient {
22✔
1002
                    &mut self.s2c_buf
5✔
1003
                } else {
1004
                    &mut self.c2s_buf
17✔
1005
                };
1006
                if head.stream_id == buf.stream_id {
22✔
1007
                    let max_reass = unsafe { HTTP2_MAX_REASS };
8✔
1008
                    if buf.data.len() + input.len() < max_reass {
8✔
1009
                        buf.data.extend(input);
8✔
1010
                    } else if buf.data.len() < max_reass {
8✔
1011
                        buf.data.extend(&input[..max_reass - buf.data.len()]);
×
1012
                        *reass_limit_reached = true;
×
1013
                    }
×
1014
                    if head.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS == 0 {
8✔
1015
                        let hs = parser::HTTP2FrameContinuation { blocks: Vec::new() };
5✔
1016
                        return HTTP2FrameTypeData::CONTINUATION(hs);
5✔
1017
                    }
3✔
1018
                } // else try to parse anyways
14✔
1019
                let input_reass = if head.stream_id == buf.stream_id {
17✔
1020
                    &buf.data
3✔
1021
                } else {
1022
                    input
14✔
1023
                };
1024

1025
                let dyn_headers = if dir == Direction::ToClient {
17✔
1026
                    &mut self.dynamic_headers_tc
4✔
1027
                } else {
1028
                    &mut self.dynamic_headers_ts
13✔
1029
                };
1030
                match parser::http2_parse_frame_continuation(input_reass, dyn_headers) {
17✔
1031
                    Ok((_, hs)) => {
16✔
1032
                        if head.stream_id == buf.stream_id {
16✔
1033
                            buf.stream_id = 0;
3✔
1034
                            buf.data.clear();
3✔
1035
                        }
15✔
1036
                        self.process_headers(&hs.blocks, dir);
16✔
1037
                        return HTTP2FrameTypeData::CONTINUATION(hs);
16✔
1038
                    }
1039
                    Err(Err::Incomplete(_)) => {
1040
                        if head.stream_id == buf.stream_id {
1✔
1041
                            buf.stream_id = 0;
×
1042
                            buf.data.clear();
×
1043
                        }
1✔
1044
                        if complete {
1✔
1045
                            self.set_event(HTTP2Event::InvalidFrameData);
1✔
1046
                            return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
1✔
1047
                                reason: HTTP2FrameUnhandledReason::ParsingError,
1✔
1048
                            });
1✔
1049
                        } else {
1050
                            return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
×
1051
                                reason: HTTP2FrameUnhandledReason::TooLong,
×
1052
                            });
×
1053
                        }
1054
                    }
1055
                    Err(_) => {
1056
                        if head.stream_id == buf.stream_id {
×
1057
                            buf.stream_id = 0;
×
1058
                            buf.data.clear();
×
1059
                        }
×
1060
                        self.set_event(HTTP2Event::InvalidFrameData);
×
1061
                        return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
×
1062
                            reason: HTTP2FrameUnhandledReason::ParsingError,
×
1063
                        });
×
1064
                    }
1065
                }
1066
            }
1067
            Some(parser::HTTP2FrameType::Headers) => {
1068
                if head.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS == 0 {
5,332✔
1069
                    let buf = if dir == Direction::ToClient {
47✔
1070
                        &mut self.s2c_buf
26✔
1071
                    } else {
1072
                        &mut self.c2s_buf
21✔
1073
                    };
1074
                    buf.data.clear();
47✔
1075
                    buf.data.extend(input);
47✔
1076
                    buf.stream_id = head.stream_id;
47✔
1077
                    let hs = parser::HTTP2FrameHeaders {
47✔
1078
                        padlength: None,
47✔
1079
                        priority: None,
47✔
1080
                        blocks: Vec::new(),
47✔
1081
                    };
47✔
1082
                    return HTTP2FrameTypeData::HEADERS(hs);
47✔
1083
                }
5,285✔
1084
                let dyn_headers = if dir == Direction::ToClient {
5,285✔
1085
                    &mut self.dynamic_headers_tc
2,434✔
1086
                } else {
1087
                    &mut self.dynamic_headers_ts
2,851✔
1088
                };
1089
                match parser::http2_parse_frame_headers(input, hflags, dyn_headers) {
5,285✔
1090
                    Ok((hrem, hs)) => {
4,937✔
1091
                        self.process_headers(&hs.blocks, dir);
4,937✔
1092
                        if !hrem.is_empty() {
4,937✔
1093
                            SCLogDebug!("Remaining data for HTTP2 headers");
×
1094
                            self.set_event(HTTP2Event::ExtraHeaderData);
×
1095
                        }
4,937✔
1096
                        return HTTP2FrameTypeData::HEADERS(hs);
4,937✔
1097
                    }
1098
                    Err(Err::Incomplete(_)) => {
1099
                        if complete {
348✔
1100
                            self.set_event(HTTP2Event::InvalidFrameData);
328✔
1101
                            return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
328✔
1102
                                reason: HTTP2FrameUnhandledReason::ParsingError,
328✔
1103
                            });
328✔
1104
                        } else {
1105
                            return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
20✔
1106
                                reason: HTTP2FrameUnhandledReason::TooLong,
20✔
1107
                            });
20✔
1108
                        }
1109
                    }
1110
                    Err(_) => {
1111
                        self.set_event(HTTP2Event::InvalidFrameData);
×
1112
                        return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
×
1113
                            reason: HTTP2FrameUnhandledReason::ParsingError,
×
1114
                        });
×
1115
                    }
1116
                }
1117
            }
1118
            Some(parser::HTTP2FrameType::Ping) => {
1119
                return HTTP2FrameTypeData::PING;
326✔
1120
            }
1121
            _ => {
1122
                return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
155✔
1123
                    reason: HTTP2FrameUnhandledReason::UnknownType,
155✔
1124
                });
155✔
1125
            }
1126
        }
1127
    }
24,687✔
1128

1129
    fn parse_frames(
8,120✔
1130
        &mut self, mut input: &[u8], il: usize, dir: Direction, flow: *mut Flow,
8,120✔
1131
        stream_slice: &StreamSlice,
8,120✔
1132
    ) -> AppLayerResult {
8,120✔
1133
        while !input.is_empty() {
34,036✔
1134
            match parser::http2_parse_frame_header(input) {
26,326✔
1135
                Ok((rem, head)) => {
26,248✔
1136
                    let hl = head.length as usize;
26,248✔
1137

26,248✔
1138
                    //we check for completeness first
26,248✔
1139
                    if rem.len() < hl {
26,248✔
1140
                        //but limit ourselves so as not to exhaust memory
1141
                        if hl < HTTP2_MAX_HANDLED_FRAME_SIZE {
494✔
1142
                            return AppLayerResult::incomplete(
134✔
1143
                                (il - input.len()) as u32,
134✔
1144
                                (HTTP2_FRAME_HEADER_LEN + hl) as u32,
134✔
1145
                            );
134✔
1146
                        } else if rem.len() < HTTP2_MIN_HANDLED_FRAME_SIZE {
360✔
1147
                            return AppLayerResult::incomplete(
198✔
1148
                                (il - input.len()) as u32,
198✔
1149
                                (HTTP2_FRAME_HEADER_LEN + HTTP2_MIN_HANDLED_FRAME_SIZE) as u32,
198✔
1150
                            );
198✔
1151
                        } else {
162✔
1152
                            self.set_event(HTTP2Event::LongFrameData);
162✔
1153
                            self.request_frame_size = head.length - (rem.len() as u32);
162✔
1154
                        }
162✔
1155
                    }
25,754✔
1156

1157
                    //get a safe length for the buffer
1158
                    let (hlsafe, complete) = if rem.len() < hl {
25,916✔
1159
                        (rem.len(), false)
162✔
1160
                    } else {
1161
                        (hl, true)
25,754✔
1162
                    };
1163

1164
                    let frame_hdr = Frame::new(
25,916✔
1165
                        flow,
25,916✔
1166
                        stream_slice,
25,916✔
1167
                        input,
25,916✔
1168
                        HTTP2_FRAME_HEADER_LEN as i64,
25,916✔
1169
                        Http2FrameType::Hdr as u8,
25,916✔
1170
                        None,
25,916✔
1171
                    );
25,916✔
1172
                    let frame_data = Frame::new(
25,916✔
1173
                        flow,
25,916✔
1174
                        stream_slice,
25,916✔
1175
                        &input[HTTP2_FRAME_HEADER_LEN..],
25,916✔
1176
                        head.length as i64,
25,916✔
1177
                        Http2FrameType::Data as u8,
25,916✔
1178
                        None,
25,916✔
1179
                    );
25,916✔
1180
                    let frame_pdu = Frame::new(
25,916✔
1181
                        flow,
25,916✔
1182
                        stream_slice,
25,916✔
1183
                        input,
25,916✔
1184
                        HTTP2_FRAME_HEADER_LEN as i64 + head.length as i64,
25,916✔
1185
                        Http2FrameType::Pdu as u8,
25,916✔
1186
                        None,
25,916✔
1187
                    );
25,916✔
1188
                    if head.length == 0 && head.ftype == parser::HTTP2FrameType::Settings as u8 {
25,916✔
1189
                        input = &rem[hlsafe..];
1,229✔
1190
                        continue;
1,229✔
1191
                    }
24,687✔
1192
                    let mut reass_limit_reached = false;
24,687✔
1193
                    let txdata = self.parse_frame_data(
24,687✔
1194
                        &head,
24,687✔
1195
                        &rem[..hlsafe],
24,687✔
1196
                        complete,
24,687✔
1197
                        dir,
24,687✔
1198
                        &mut reass_limit_reached,
24,687✔
1199
                    );
24,687✔
1200

24,687✔
1201
                    let tx = self.find_or_create_tx(&head, &txdata, dir);
24,687✔
1202
                    if tx.is_none() {
24,687✔
1203
                        return AppLayerResult::err();
×
1204
                    }
24,687✔
1205
                    let tx = tx.unwrap();
24,687✔
1206
                    if let Some(frame) = frame_hdr {
24,687✔
1207
                        frame.set_tx(flow, tx.tx_id);
9,798✔
1208
                    }
14,889✔
1209
                    if let Some(frame) = frame_data {
24,687✔
1210
                        frame.set_tx(flow, tx.tx_id);
9,798✔
1211
                    }
14,889✔
1212
                    if let Some(frame) = frame_pdu {
24,687✔
1213
                        frame.set_tx(flow, tx.tx_id);
9,798✔
1214
                    }
14,889✔
1215
                    if let Some(doh_req_buf) = tx.handle_frame(&head, &txdata, dir) {
24,687✔
1216
                        if let Ok(mut dtx) = dns_parse_request(&doh_req_buf, &DnsVariant::Dns) {
175✔
1217
                            dtx.id = 1;
168✔
1218
                            unsafe {
168✔
1219
                                SCAppLayerForceProtocolChange(flow, ALPROTO_DOH2);
168✔
1220
                            }
168✔
1221
                            if let Some(doh) = &mut tx.doh {
168✔
1222
                                doh.dns_request_tx = Some(dtx);
×
1223
                            } else {
168✔
1224
                                let doh = DohHttp2Tx {
168✔
1225
                                    dns_request_tx: Some(dtx),
168✔
1226
                                    ..Default::default()
168✔
1227
                                };
168✔
1228
                                tx.doh = Some(doh);
168✔
1229
                            }
168✔
1230
                        }
7✔
1231
                    }
24,512✔
1232
                    if reass_limit_reached {
24,687✔
1233
                        tx.tx_data
×
1234
                            .set_event(HTTP2Event::ReassemblyLimitReached as u8);
×
1235
                    }
24,687✔
1236
                    let over = head.flags & parser::HTTP2_FLAG_HEADER_EOS != 0;
24,687✔
1237
                    let ftype = head.ftype;
24,687✔
1238
                    let sid = head.stream_id;
24,687✔
1239
                    let padded = head.flags & parser::HTTP2_FLAG_HEADER_PADDED != 0;
24,687✔
1240
                    let h2frames = if dir == Direction::ToServer {
24,687✔
1241
                        &mut tx.frames_ts
9,941✔
1242
                    } else {
1243
                        &mut tx.frames_tc
14,746✔
1244
                    };
1245
                    if h2frames.len() < unsafe { HTTP2_MAX_FRAMES } {
24,687✔
1246
                        h2frames.push(HTTP2Frame {
24,687✔
1247
                            header: head,
24,687✔
1248
                            data: txdata,
24,687✔
1249
                        });
24,687✔
1250
                    } else {
24,687✔
1251
                        tx.tx_data.set_event(HTTP2Event::TooManyFrames as u8);
×
1252
                    }
×
1253
                    if ftype == parser::HTTP2FrameType::Data as u8 && sid == 0 {
24,687✔
1254
                        tx.tx_data.set_event(HTTP2Event::DataStreamZero as u8);
4,840✔
1255
                    } else if ftype == parser::HTTP2FrameType::Data as u8 && sid > 0 {
19,847✔
1256
                        match unsafe { SURICATA_HTTP2_FILE_CONFIG } {
8,039✔
1257
                            Some(sfcm) => {
8,039✔
1258
                                //borrow checker forbids to reuse directly tx
8,039✔
1259
                                let index = self.find_tx_index(sid);
8,039✔
1260
                                if index > 0 {
8,039✔
1261
                                    let tx_same = &mut self.transactions[index - 1];
8,039✔
1262
                                    if dir == Direction::ToServer {
8,039✔
1263
                                        tx_same.ft_tc.tx_id = tx_same.tx_id - 1;
2,201✔
1264
                                    } else {
5,838✔
1265
                                        tx_same.ft_ts.tx_id = tx_same.tx_id - 1;
5,838✔
1266
                                    };
5,838✔
1267
                                    let mut dinput = &rem[..hlsafe];
8,039✔
1268
                                    if padded && !rem.is_empty() && usize::from(rem[0]) < hlsafe {
8,039✔
1269
                                        dinput = &rem[1..hlsafe - usize::from(rem[0])];
157✔
1270
                                    }
7,882✔
1271
                                    let mut output = Vec::with_capacity(
8,039✔
1272
                                        decompression::HTTP2_DECOMPRESSION_CHUNK_SIZE,
8,039✔
1273
                                    );
8,039✔
1274
                                    match tx_same.decompress(
8,039✔
1275
                                        dinput,
8,039✔
1276
                                        &mut output,
8,039✔
1277
                                        dir,
8,039✔
1278
                                        sfcm,
8,039✔
1279
                                        over,
8,039✔
1280
                                        flow,
8,039✔
1281
                                    ) {
8,039✔
1282
                                        Ok(_) => {
1283
                                            if over {
7,976✔
1284
                                                tx_same.handle_dns_data(dir, flow);
4,249✔
1285
                                            }
4,875✔
1286
                                        }
1287
                                        _ => {
63✔
1288
                                            self.set_event(HTTP2Event::FailedDecompression);
63✔
1289
                                        }
63✔
1290
                                    }
1291
                                }
×
1292
                            }
1293
                            None => panic!("no SURICATA_HTTP2_FILE_CONFIG"),
×
1294
                        }
1295
                    }
11,808✔
1296
                    sc_app_layer_parser_trigger_raw_stream_inspection(flow, dir as i32);
24,687✔
1297
                    input = &rem[hlsafe..];
24,687✔
1298
                }
1299
                Err(Err::Incomplete(_)) => {
1300
                    //we may have consumed data from previous records
1301
                    return AppLayerResult::incomplete(
78✔
1302
                        (il - input.len()) as u32,
78✔
1303
                        HTTP2_FRAME_HEADER_LEN as u32,
78✔
1304
                    );
78✔
1305
                }
1306
                Err(_) => {
1307
                    self.set_event(HTTP2Event::InvalidFrameHeader);
×
1308
                    return AppLayerResult::err();
×
1309
                }
1310
            }
1311
        }
1312
        return AppLayerResult::ok();
7,710✔
1313
    }
8,120✔
1314

1315
    fn parse_ts(&mut self, flow: *mut Flow, stream_slice: StreamSlice) -> AppLayerResult {
4,363✔
1316
        //very first : skip magic
4,363✔
1317
        let mut input = stream_slice.as_slice();
4,363✔
1318
        let mut magic_consumed = 0;
4,363✔
1319
        if self.progress < HTTP2ConnectionState::Http2StateMagicDone {
4,363✔
1320
            //skip magic
1321
            if input.len() >= HTTP2_MAGIC_LEN {
1,089✔
1322
                //skip magic
1323
                match std::str::from_utf8(&input[..HTTP2_MAGIC_LEN]) {
1,088✔
1324
                    Ok("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n") => {
1,085✔
1325
                        input = &input[HTTP2_MAGIC_LEN..];
1,036✔
1326
                        magic_consumed = HTTP2_MAGIC_LEN;
1,036✔
1327
                    }
1,036✔
1328
                    Ok(&_) => {
49✔
1329
                        self.set_event(HTTP2Event::InvalidClientMagic);
49✔
1330
                    }
49✔
1331
                    Err(_) => {
1332
                        return AppLayerResult::err();
3✔
1333
                    }
1334
                }
1335
                self.progress = HTTP2ConnectionState::Http2StateMagicDone;
1,085✔
1336
            } else {
1337
                //still more buffer
1338
                return AppLayerResult::incomplete(0_u32, HTTP2_MAGIC_LEN as u32);
1✔
1339
            }
1340
        }
3,274✔
1341
        //first consume frame bytes
1342
        let il = input.len();
4,359✔
1343
        if self.request_frame_size > 0 {
4,359✔
1344
            let ilen = input.len() as u32;
246✔
1345
            if self.request_frame_size >= ilen {
246✔
1346
                self.request_frame_size -= ilen;
246✔
1347
                return AppLayerResult::ok();
246✔
1348
            } else {
×
1349
                let start = self.request_frame_size as usize;
×
1350
                input = &input[start..];
×
1351
                self.request_frame_size = 0;
×
1352
            }
×
1353
        }
4,113✔
1354

1355
        //then parse all we can
1356
        let r = self.parse_frames(input, il, Direction::ToServer, flow, &stream_slice);
4,113✔
1357
        if r.status == 1 {
4,113✔
1358
            //adds bytes consumed by banner to incomplete result
1359
            return AppLayerResult::incomplete(r.consumed + magic_consumed as u32, r.needed);
277✔
1360
        } else {
1361
            return r;
3,836✔
1362
        }
1363
    }
4,363✔
1364

1365
    fn parse_tc(&mut self, flow: *mut Flow, stream_slice: StreamSlice) -> AppLayerResult {
4,007✔
1366
        //first consume frame bytes
4,007✔
1367
        let mut input = stream_slice.as_slice();
4,007✔
1368
        let il = input.len();
4,007✔
1369
        if self.response_frame_size > 0 {
4,007✔
1370
            let ilen = input.len() as u32;
×
1371
            if self.response_frame_size >= ilen {
×
1372
                self.response_frame_size -= ilen;
×
1373
                return AppLayerResult::ok();
×
1374
            } else {
×
1375
                let start = self.response_frame_size as usize;
×
1376
                input = &input[start..];
×
1377
                self.response_frame_size = 0;
×
1378
            }
×
1379
        }
4,007✔
1380
        //then parse all we can
1381
        return self.parse_frames(input, il, Direction::ToClient, flow, &stream_slice);
4,007✔
1382
    }
4,007✔
1383
}
1384

1385
// C exports.
1386

1387
#[no_mangle]
1388
pub unsafe extern "C" fn SCDoH2GetDnsTx(
8,178✔
1389
    tx: &HTTP2Transaction, flags: u8,
8,178✔
1390
) -> *mut std::os::raw::c_void {
8,178✔
1391
    if let Some(doh) = &tx.doh {
8,178✔
1392
        if flags & Direction::ToServer as u8 != 0 {
6,813✔
1393
            if let Some(ref dtx) = &doh.dns_request_tx {
2,367✔
1394
                return dtx as *const _ as *mut _;
2,223✔
1395
            }
144✔
1396
        } else if flags & Direction::ToClient as u8 != 0 {
4,446✔
1397
            if let Some(ref dtx) = &doh.dns_response_tx {
4,446✔
1398
                return dtx as *const _ as *mut _;
3,108✔
1399
            }
1,338✔
1400
        }
×
1401
    }
1,365✔
1402
    std::ptr::null_mut()
2,847✔
1403
}
8,178✔
1404

1405
export_tx_data_get!(http2_get_tx_data, HTTP2Transaction);
1406
export_state_data_get!(http2_get_state_data, HTTP2State);
1407

1408
/// C entry point for a probing parser.
1409
unsafe extern "C" fn http2_probing_parser_tc(
1,890✔
1410
    _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8,
1,890✔
1411
) -> AppProto {
1,890✔
1412
    if !input.is_null() {
1,890✔
1413
        let slice = build_slice!(input, input_len as usize);
1,890✔
1414
        match parser::http2_parse_frame_header(slice) {
1,890✔
1415
            Ok((_, header)) => {
1,890✔
1416
                if header.reserved != 0
1,890✔
1417
                    || header.length > HTTP2_DEFAULT_MAX_FRAME_SIZE
1,852✔
1418
                    || header.flags & 0xFE != 0
1,632✔
1419
                    || header.ftype != parser::HTTP2FrameType::Settings as u8
1,584✔
1420
                {
1421
                    return ALPROTO_FAILED;
990✔
1422
                }
900✔
1423
                return ALPROTO_HTTP2;
900✔
1424
            }
1425
            Err(Err::Incomplete(_)) => {
1426
                return ALPROTO_UNKNOWN;
×
1427
            }
1428
            Err(_) => {
1429
                return ALPROTO_FAILED;
×
1430
            }
1431
        }
1432
    }
×
1433
    return ALPROTO_UNKNOWN;
×
1434
}
1,890✔
1435

1436
// Suppress the unsafe warning here as creating a state for an app-layer
1437
// is typically not unsafe.
1438
#[allow(clippy::not_unsafe_ptr_arg_deref)]
1439
extern "C" fn http2_state_new(
1,209✔
1440
    orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto,
1,209✔
1441
) -> *mut std::os::raw::c_void {
1,209✔
1442
    let state = HTTP2State::new();
1,209✔
1443
    let boxed = Box::new(state);
1,209✔
1444
    let r = Box::into_raw(boxed) as *mut _;
1,209✔
1445
    if !orig_state.is_null() {
1,209✔
1446
        //we could check ALPROTO_HTTP1 == orig_proto
1447
        unsafe {
275✔
1448
            SCHTTP2MimicHttp1Request(orig_state, r);
275✔
1449
        }
275✔
1450
    }
934✔
1451
    return r;
1,209✔
1452
}
1,209✔
1453

1454
unsafe extern "C" fn http2_state_free(state: *mut std::os::raw::c_void) {
1,209✔
1455
    let mut state: Box<HTTP2State> = Box::from_raw(state as _);
1,209✔
1456
    state.free();
1,209✔
1457
}
1,209✔
1458

1459
unsafe extern "C" fn http2_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) {
9,630✔
1460
    let state = cast_pointer!(state, HTTP2State);
9,630✔
1461
    state.free_tx(tx_id);
9,630✔
1462
}
9,630✔
1463

1464
unsafe extern "C" fn http2_parse_ts(
4,363✔
1465
    flow: *mut Flow, state: *mut std::os::raw::c_void, _pstate: *mut AppLayerParserState,
4,363✔
1466
    stream_slice: StreamSlice, _data: *mut std::os::raw::c_void,
4,363✔
1467
) -> AppLayerResult {
4,363✔
1468
    let state = cast_pointer!(state, HTTP2State);
4,363✔
1469
    return state.parse_ts(flow, stream_slice);
4,363✔
1470
}
4,363✔
1471

1472
unsafe extern "C" fn http2_parse_tc(
4,007✔
1473
    flow: *mut Flow, state: *mut std::os::raw::c_void, _pstate: *mut AppLayerParserState,
4,007✔
1474
    stream_slice: StreamSlice, _data: *mut std::os::raw::c_void,
4,007✔
1475
) -> AppLayerResult {
4,007✔
1476
    let state = cast_pointer!(state, HTTP2State);
4,007✔
1477
    return state.parse_tc(flow, stream_slice);
4,007✔
1478
}
4,007✔
1479

1480
unsafe extern "C" fn http2_state_get_tx(
9,120✔
1481
    state: *mut std::os::raw::c_void, tx_id: u64,
9,120✔
1482
) -> *mut std::os::raw::c_void {
9,120✔
1483
    let state = cast_pointer!(state, HTTP2State);
9,120✔
1484
    match state.get_tx(tx_id) {
9,120✔
1485
        Some(tx) => {
9,120✔
1486
            return tx as *const _ as *mut _;
9,120✔
1487
        }
1488
        None => {
1489
            return std::ptr::null_mut();
×
1490
        }
1491
    }
1492
}
9,120✔
1493

1494
unsafe extern "C" fn http2_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 {
58,527✔
1495
    let state = cast_pointer!(state, HTTP2State);
58,527✔
1496
    return state.tx_id;
58,527✔
1497
}
58,527✔
1498

1499
unsafe extern "C" fn http2_tx_get_state(tx: *mut std::os::raw::c_void) -> HTTP2TransactionState {
381,993✔
1500
    let tx = cast_pointer!(tx, HTTP2Transaction);
381,993✔
1501
    return tx.state;
381,993✔
1502
}
381,993✔
1503

1504
unsafe extern "C" fn http2_tx_get_alstate_progress(
381,993✔
1505
    tx: *mut std::os::raw::c_void, _direction: u8,
381,993✔
1506
) -> std::os::raw::c_int {
381,993✔
1507
    return http2_tx_get_state(tx) as i32;
381,993✔
1508
}
381,993✔
1509

1510
unsafe extern "C" fn http2_getfiles(
161,152✔
1511
    tx: *mut std::os::raw::c_void, direction: u8,
161,152✔
1512
) -> AppLayerGetFileState {
161,152✔
1513
    let tx = cast_pointer!(tx, HTTP2Transaction);
161,152✔
1514
    if let Some(sfcm) = { SURICATA_HTTP2_FILE_CONFIG } {
161,152✔
1515
        if direction & STREAM_TOSERVER != 0 {
161,152✔
1516
            return AppLayerGetFileState {
80,360✔
1517
                fc: &mut tx.ft_ts.file,
80,360✔
1518
                cfg: sfcm.files_sbcfg,
80,360✔
1519
            };
80,360✔
1520
        } else {
1521
            return AppLayerGetFileState {
80,792✔
1522
                fc: &mut tx.ft_tc.file,
80,792✔
1523
                cfg: sfcm.files_sbcfg,
80,792✔
1524
            };
80,792✔
1525
        }
1526
    }
×
1527
    AppLayerGetFileState::err()
×
1528
}
161,152✔
1529

1530
// Parser name as a C style string.
1531
const PARSER_NAME: &[u8] = b"http2\0";
1532

1533
#[no_mangle]
1534
pub unsafe extern "C" fn SCRegisterHttp2Parser() {
2,226✔
1535
    let default_port = CString::new("[80]").unwrap();
2,226✔
1536
    let mut parser = RustParser {
2,226✔
1537
        name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
2,226✔
1538
        default_port: default_port.as_ptr(),
2,226✔
1539
        ipproto: IPPROTO_TCP,
2,226✔
1540
        probe_ts: None, // big magic string should be enough
2,226✔
1541
        probe_tc: Some(http2_probing_parser_tc),
2,226✔
1542
        min_depth: HTTP2_FRAME_HEADER_LEN as u16,
2,226✔
1543
        max_depth: HTTP2_MAGIC_LEN as u16,
2,226✔
1544
        state_new: http2_state_new,
2,226✔
1545
        state_free: http2_state_free,
2,226✔
1546
        tx_free: http2_state_tx_free,
2,226✔
1547
        parse_ts: http2_parse_ts,
2,226✔
1548
        parse_tc: http2_parse_tc,
2,226✔
1549
        get_tx_count: http2_state_get_tx_count,
2,226✔
1550
        get_tx: http2_state_get_tx,
2,226✔
1551
        tx_comp_st_ts: HTTP2TransactionState::HTTP2StateClosed as i32,
2,226✔
1552
        tx_comp_st_tc: HTTP2TransactionState::HTTP2StateClosed as i32,
2,226✔
1553
        tx_get_progress: http2_tx_get_alstate_progress,
2,226✔
1554
        get_eventinfo: Some(HTTP2Event::get_event_info),
2,226✔
1555
        get_eventinfo_byid: Some(HTTP2Event::get_event_info_by_id),
2,226✔
1556
        localstorage_new: None,
2,226✔
1557
        localstorage_free: None,
2,226✔
1558
        get_tx_files: Some(http2_getfiles),
2,226✔
1559
        get_tx_iterator: Some(applayer::state_get_tx_iterator::<HTTP2State, HTTP2Transaction>),
2,226✔
1560
        get_tx_data: http2_get_tx_data,
2,226✔
1561
        get_state_data: http2_get_state_data,
2,226✔
1562
        apply_tx_config: None,
2,226✔
1563
        flags: 0,
2,226✔
1564
        get_frame_id_by_name: Some(Http2FrameType::ffi_id_from_name),
2,226✔
1565
        get_frame_name_by_id: Some(Http2FrameType::ffi_name_from_id),
2,226✔
1566
        get_state_id_by_name: None,
2,226✔
1567
        get_state_name_by_id: None,
2,226✔
1568
    };
2,226✔
1569

2,226✔
1570
    let ip_proto_str = CString::new("tcp").unwrap();
2,226✔
1571

2,226✔
1572
    if SCAppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
2,226✔
1573
        let alproto = applayer_register_protocol_detection(&parser, 1);
2,226✔
1574
        ALPROTO_HTTP2 = alproto;
2,226✔
1575
        if SCAppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
2,226✔
1576
            let _ = AppLayerRegisterParser(&parser, alproto);
2,226✔
1577
        }
2,226✔
1578
        if let Some(val) = conf_get("app-layer.protocols.http2.max-streams") {
2,226✔
1579
            if let Ok(v) = val.parse::<usize>() {
×
1580
                HTTP2_MAX_STREAMS = v;
×
1581
            } else {
×
1582
                SCLogError!("Invalid value for http2.max-streams");
×
1583
            }
1584
        }
2,226✔
1585
        if let Some(val) = conf_get("app-layer.protocols.http2.max-frames") {
2,226✔
1586
            if let Ok(v) = val.parse::<usize>() {
×
1587
                HTTP2_MAX_FRAMES = v;
×
1588
            } else {
×
1589
                SCLogError!("Invalid value for http2.max-frames");
×
1590
            }
1591
        }
2,226✔
1592
        if let Some(val) = conf_get("app-layer.protocols.http2.max-table-size") {
2,226✔
1593
            if let Ok(v) = val.parse::<u32>() {
×
1594
                HTTP2_MAX_TABLESIZE = v;
×
1595
            } else {
×
1596
                SCLogError!("Invalid value for http2.max-table-size");
×
1597
            }
1598
        }
2,226✔
1599
        if let Some(val) = conf_get("app-layer.protocols.http2.max-reassembly-size") {
2,226✔
1600
            if let Ok(v) = val.parse::<u32>() {
×
1601
                HTTP2_MAX_REASS = v as usize;
×
1602
            } else {
×
1603
                SCLogError!("Invalid value for http2.max-reassembly-size");
×
1604
            }
1605
        }
2,226✔
1606
        SCAppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP2);
2,226✔
1607
        SCLogDebug!("Rust http2 parser registered.");
1608
    } else {
1609
        SCLogNotice!("Protocol detector and parser disabled for HTTP2.");
×
1610
    }
1611

1612
    // doh2 is just http2 wrapped in another name
1613
    parser.name = b"doh2\0".as_ptr() as *const std::os::raw::c_char;
2,226✔
1614
    parser.probe_tc = None;
2,226✔
1615
    parser.default_port = std::ptr::null();
2,226✔
1616
    if SCAppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
2,226✔
1617
        let alproto = applayer_register_protocol_detection(&parser, 1);
2,226✔
1618
        ALPROTO_DOH2 = alproto;
2,226✔
1619
        if SCAppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
2,226✔
1620
            let _ = AppLayerRegisterParser(&parser, alproto);
2,226✔
1621
        } else {
2,226✔
1622
            SCLogWarning!("DOH2 is not meant to be detection-only.");
×
1623
        }
1624
        SCAppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DOH2);
2,226✔
1625
        SCLogDebug!("Rust doh2 parser registered.");
1626
    } else {
1627
        SCLogNotice!("Protocol detector and parser disabled for DOH2.");
×
1628
    }
1629
}
2,226✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc