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

jasonish / suricata / 23019292042

12 Mar 2026 07:08PM UTC coverage: 79.245% (-0.004%) from 79.249%
23019292042

push

github

jasonish
github-ci: add schema ordering check for yaml schema

266163 of 335873 relevant lines covered (79.25%)

4877167.7 hits per line

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

83.02
/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

83
#[derive(AppLayerFrameType)]
84
pub enum Http2FrameType {
85
    Hdr,
86
    Data,
87
    Pdu,
88
}
89

90
#[repr(u8)]
91
#[derive(Copy, Clone, PartialOrd, PartialEq, Eq, Debug)]
92
pub enum HTTP2FrameUnhandledReason {
93
    UnknownType = 0,
94
    TooLong = 1,
95
    ParsingError = 2,
96
    Incomplete = 3,
97
}
98

99
impl fmt::Display for HTTP2FrameUnhandledReason {
100
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
×
101
        write!(f, "{:?}", self)
×
102
    }
×
103
}
104

105
#[derive(Debug)]
106
pub struct HTTP2FrameUnhandled {
107
    pub reason: HTTP2FrameUnhandledReason,
108
}
109

110
#[derive(Debug)]
111
pub enum HTTP2FrameTypeData {
112
    PRIORITY(parser::HTTP2FramePriority),
113
    GOAWAY(parser::HTTP2FrameGoAway),
114
    RSTSTREAM(parser::HTTP2FrameRstStream),
115
    SETTINGS(Vec<parser::HTTP2FrameSettings>),
116
    WINDOWUPDATE(parser::HTTP2FrameWindowUpdate),
117
    HEADERS(parser::HTTP2FrameHeaders),
118
    PUSHPROMISE(parser::HTTP2FramePushPromise),
119
    CONTINUATION(parser::HTTP2FrameContinuation),
120
    PING,
121
    DATA,
122
    //not a defined frame
123
    UNHANDLED(HTTP2FrameUnhandled),
124
}
125

126
#[repr(u8)]
127
#[derive(Copy, Clone, PartialOrd, PartialEq, Eq, Debug)]
128
pub enum HTTP2TransactionState {
129
    HTTP2StateIdle = 0,
130
    HTTP2StateOpen = 1,
131
    HTTP2StateReserved = 2,
132
    HTTP2StateDataClient = 3,
133
    HTTP2StateHalfClosedClient = 4,
134
    HTTP2StateDataServer = 5,
135
    HTTP2StateHalfClosedServer = 6,
136
    HTTP2StateClosed = 7,
137
    //not a RFC-defined state, used for stream 0 frames applying to the global connection
138
    HTTP2StateGlobal = 8,
139
    //not a RFC-defined state, dropping this old tx because we have too many
140
    HTTP2StateTodrop = 9,
141
}
142

143
#[derive(Debug)]
144
pub struct HTTP2Frame {
145
    pub header: parser::HTTP2FrameHeader,
146
    pub data: HTTP2FrameTypeData,
147
}
148

149
#[derive(Debug, Default)]
150
/// Dns Over HTTP2 Data inside a HTTP2 transaction
151
pub struct DohHttp2Tx {
152
    /// wether the HTTP2 data is DNS, for both directions
153
    is_doh_data: [bool; 2],
154
    /// http2 data buffer to parse as DNS on completion
155
    pub data_buf: [Vec<u8>; 2],
156
    /// dns request transation
157
    pub dns_request_tx: Option<DNSTransaction>,
158
    /// dns response transation
159
    pub dns_response_tx: Option<DNSTransaction>,
160
}
161

162
#[derive(Debug)]
163
pub struct HTTP2Transaction {
164
    tx_id: u64,
165
    pub stream_id: u32,
166
    pub state: HTTP2TransactionState,
167
    child_stream_id: u32,
168

169
    pub frames_tc: Vec<HTTP2Frame>,
170
    pub frames_ts: Vec<HTTP2Frame>,
171

172
    decoder: decompression::HTTP2Decoder,
173
    pub file_range: *mut HttpRangeContainerBlock,
174

175
    pub tx_data: AppLayerTxData,
176
    pub ft_tc: FileTransferTracker,
177
    pub ft_ts: FileTransferTracker,
178

179
    pub req_line: Vec<u8>,
180
    pub resp_line: Vec<u8>,
181

182
    pub doh: Option<DohHttp2Tx>,
183
}
184

185
impl Transaction for HTTP2Transaction {
186
    fn id(&self) -> u64 {
707,494✔
187
        self.tx_id
707,494✔
188
    }
707,494✔
189
}
190

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

572
    c2s_buf: HTTP2HeaderReassemblyBuffer,
573
    s2c_buf: HTTP2HeaderReassemblyBuffer,
574
}
575

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

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

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

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

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

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

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

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

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

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

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

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

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

807
    fn process_headers(&mut self, blocks: &Vec<parser::HTTP2FrameHeaderBlock>, dir: Direction) {
4,950✔
808
        let (mut update, mut sizeup) = (false, 0);
4,950✔
809
        for block in blocks {
70,206✔
810
            if block.error >= parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeError {
65,256✔
811
                self.set_event(HTTP2Event::InvalidHeader);
6,134✔
812
            } else if block.error == parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate {
59,122✔
813
                update = true;
944✔
814
                if block.sizeupdate > sizeup {
944✔
815
                    sizeup = block.sizeupdate;
539✔
816
                }
539✔
817
            } else if block.error
58,178✔
818
                == parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeIntegerOverflow
58,178✔
819
            {
×
820
                self.set_event(HTTP2Event::HeaderIntegerOverflow);
×
821
            }
58,178✔
822
        }
823
        if update {
4,950✔
824
            //borrow checker forbids to pass directly dyn_headers
825
            let dyn_headers = if dir == Direction::ToClient {
469✔
826
                &mut self.dynamic_headers_tc
371✔
827
            } else {
828
                &mut self.dynamic_headers_ts
98✔
829
            };
830
            dyn_headers.max_size = sizeup as usize;
469✔
831
        }
4,481✔
832
    }
4,950✔
833

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

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

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

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

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

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

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

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

1351
        //then parse all we can
1352
        let r = self.parse_frames(input, il, Direction::ToServer, flow, &stream_slice);
4,108✔
1353
        if r.status == 1 {
4,108✔
1354
            //adds bytes consumed by banner to incomplete result
1355
            return AppLayerResult::incomplete(r.consumed + magic_consumed as u32, r.needed);
277✔
1356
        } else {
1357
            return r;
3,831✔
1358
        }
1359
    }
4,358✔
1360

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

1381
// C exports.
1382

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

1401
export_tx_data_get!(http2_get_tx_data, HTTP2Transaction);
1402
export_state_data_get!(http2_get_state_data, HTTP2State);
1403

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

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

1450
unsafe extern "C" fn http2_state_free(state: *mut std::os::raw::c_void) {
1,208✔
1451
    let mut state: Box<HTTP2State> = Box::from_raw(state as _);
1,208✔
1452
    state.free();
1,208✔
1453
}
1,208✔
1454

1455
unsafe extern "C" fn http2_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) {
9,620✔
1456
    let state = cast_pointer!(state, HTTP2State);
9,620✔
1457
    state.free_tx(tx_id);
9,620✔
1458
}
9,620✔
1459

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

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

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

1490
unsafe extern "C" fn http2_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 {
58,482✔
1491
    let state = cast_pointer!(state, HTTP2State);
58,482✔
1492
    return state.tx_id;
58,482✔
1493
}
58,482✔
1494

1495
unsafe extern "C" fn http2_tx_get_state(tx: *mut std::os::raw::c_void) -> HTTP2TransactionState {
381,887✔
1496
    let tx = cast_pointer!(tx, HTTP2Transaction);
381,887✔
1497
    return tx.state;
381,887✔
1498
}
381,887✔
1499

1500
unsafe extern "C" fn http2_tx_get_alstate_progress(
381,887✔
1501
    tx: *mut std::os::raw::c_void, _direction: u8,
381,887✔
1502
) -> std::os::raw::c_int {
381,887✔
1503
    return http2_tx_get_state(tx) as i32;
381,887✔
1504
}
381,887✔
1505

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

1526
// Parser name as a C style string.
1527
const PARSER_NAME: &[u8] = b"http2\0";
1528

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

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

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

1601
    // doh2 is just http2 wrapped in another name
1602
    parser.name = b"doh2\0".as_ptr() as *const std::os::raw::c_char;
2,226✔
1603
    parser.probe_tc = None;
2,226✔
1604
    parser.default_port = std::ptr::null();
2,226✔
1605
    if SCAppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
2,226✔
1606
        let alproto = applayer_register_protocol_detection(&parser, 1);
2,226✔
1607
        ALPROTO_DOH2 = alproto;
2,226✔
1608
        if SCAppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
2,226✔
1609
            let _ = AppLayerRegisterParser(&parser, alproto);
2,226✔
1610
        } else {
2,226✔
1611
            SCLogWarning!("DOH2 is not meant to be detection-only.");
×
1612
        }
1613
        SCAppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DOH2);
2,226✔
1614
        SCLogDebug!("Rust doh2 parser registered.");
1615
    } else {
1616
        SCLogNotice!("Protocol detector and parser disabled for DOH2.");
×
1617
    }
1618
}
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