]> git.ipfire.org Git - people/ms/suricata.git/blame - rust/src/http2/http2.rs
range: prevents memory leak of file from HTTP2
[people/ms/suricata.git] / rust / src / http2 / http2.rs
CommitLineData
1422b18a
PA
1/* Copyright (C) 2020 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
d8612282 18use super::decompression;
98f84d5a 19use super::detect;
1422b18a 20use super::parser;
98f84d5a
PA
21use super::range;
22
1422b18a 23use crate::applayer::{self, *};
ee5b300c 24use crate::core::{self, *};
1422b18a
PA
25use crate::filecontainer::*;
26use crate::filetracker::*;
1422b18a
PA
27use nom;
28use std;
cef2832d 29use std::ffi::CString;
1422b18a 30use std::fmt;
d8612282 31use std::io;
1422b18a
PA
32
33static mut ALPROTO_HTTP2: AppProto = ALPROTO_UNKNOWN;
34
35const HTTP2_DEFAULT_MAX_FRAME_SIZE: u32 = 16384;
36const HTTP2_MAX_HANDLED_FRAME_SIZE: usize = 65536;
37const HTTP2_MIN_HANDLED_FRAME_SIZE: usize = 256;
38
39pub static mut SURICATA_HTTP2_FILE_CONFIG: Option<&'static SuricataFileContext> = None;
40
41#[no_mangle]
42pub extern "C" fn rs_http2_init(context: &'static mut SuricataFileContext) {
43 unsafe {
44 SURICATA_HTTP2_FILE_CONFIG = Some(context);
45 }
46}
47
48#[repr(u8)]
49#[derive(Copy, Clone, PartialOrd, PartialEq)]
50pub enum HTTP2ConnectionState {
51 Http2StateInit = 0,
52 Http2StateMagicDone = 1,
53}
54
55const HTTP2_FRAME_HEADER_LEN: usize = 9;
56const HTTP2_MAGIC_LEN: usize = 24;
57const HTTP2_FRAME_GOAWAY_LEN: usize = 4;
58const HTTP2_FRAME_RSTSTREAM_LEN: usize = 4;
64fcba22 59const HTTP2_FRAME_PRIORITY_LEN: usize = 5;
1422b18a 60const HTTP2_FRAME_WINDOWUPDATE_LEN: usize = 4;
c300a859
PA
61//TODO make this configurable
62pub const HTTP2_MAX_TABLESIZE: u32 = 0x10000; // 65536
1422b18a
PA
63
64#[repr(u8)]
65#[derive(Copy, Clone, PartialOrd, PartialEq, Debug)]
66pub enum HTTP2FrameUnhandledReason {
67 UnknownType = 0,
68 TooLong = 1,
69 ParsingError = 2,
70 Incomplete = 3,
71}
72
73impl fmt::Display for HTTP2FrameUnhandledReason {
74 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75 write!(f, "{:?}", self)
76 }
77}
78
79#[derive(Debug)]
80pub struct HTTP2FrameUnhandled {
81 pub reason: HTTP2FrameUnhandledReason,
82}
83
20e8f909 84#[derive(Debug)]
1422b18a
PA
85pub enum HTTP2FrameTypeData {
86 PRIORITY(parser::HTTP2FramePriority),
87 GOAWAY(parser::HTTP2FrameGoAway),
88 RSTSTREAM(parser::HTTP2FrameRstStream),
89 SETTINGS(Vec<parser::HTTP2FrameSettings>),
90 WINDOWUPDATE(parser::HTTP2FrameWindowUpdate),
91 HEADERS(parser::HTTP2FrameHeaders),
92 PUSHPROMISE(parser::HTTP2FramePushPromise),
93 CONTINUATION(parser::HTTP2FrameContinuation),
94 PING,
95 DATA,
96 //not a defined frame
97 UNHANDLED(HTTP2FrameUnhandled),
98}
99
100#[repr(u8)]
101#[derive(Copy, Clone, PartialOrd, PartialEq, Debug)]
102pub enum HTTP2TransactionState {
103 HTTP2StateIdle = 0,
104 HTTP2StateOpen = 1,
105 HTTP2StateReserved = 2,
106 HTTP2StateDataClient = 3,
b21acfbf
PA
107 HTTP2StateHalfClosedClient = 4,
108 HTTP2StateDataServer = 5,
1422b18a
PA
109 HTTP2StateHalfClosedServer = 6,
110 HTTP2StateClosed = 7,
111 //not a RFC-defined state, used for stream 0 frames appyling to the global connection
112 HTTP2StateGlobal = 8,
113}
114
20e8f909 115#[derive(Debug)]
1422b18a
PA
116pub struct HTTP2Frame {
117 pub header: parser::HTTP2FrameHeader,
118 pub data: HTTP2FrameTypeData,
119}
120
20e8f909 121#[derive(Debug)]
1422b18a
PA
122pub struct HTTP2Transaction {
123 tx_id: u64,
124 pub stream_id: u32,
7011bddf 125 pub state: HTTP2TransactionState,
1422b18a
PA
126 child_stream_id: u32,
127
128 pub frames_tc: Vec<HTTP2Frame>,
129 pub frames_ts: Vec<HTTP2Frame>,
130
d8612282 131 decoder: decompression::HTTP2Decoder,
98f84d5a 132 pub file_range: *mut HttpRangeContainerBlock,
d8612282 133
1422b18a
PA
134 events: *mut core::AppLayerDecoderEvents,
135 tx_data: AppLayerTxData,
98f84d5a 136 pub ft_tc: FileTransferTracker,
6fe8bce3 137 ft_ts: FileTransferTracker,
1422b18a
PA
138
139 //temporary escaped header for detection
140 //must be attached to transaction for memory management (be freed at the right time)
4aa80ac7 141 pub escaped: Vec<Vec<u8>>,
1422b18a
PA
142}
143
54e62ddf
JI
144impl Transaction for HTTP2Transaction {
145 fn id(&self) -> u64 {
146 self.tx_id
147 }
148}
149
1422b18a
PA
150impl HTTP2Transaction {
151 pub fn new() -> HTTP2Transaction {
152 HTTP2Transaction {
153 tx_id: 0,
154 stream_id: 0,
155 child_stream_id: 0,
156 state: HTTP2TransactionState::HTTP2StateIdle,
157 frames_tc: Vec::new(),
158 frames_ts: Vec::new(),
d8612282 159 decoder: decompression::HTTP2Decoder::new(),
98f84d5a 160 file_range: std::ptr::null_mut(),
1422b18a
PA
161 events: std::ptr::null_mut(),
162 tx_data: AppLayerTxData::new(),
6fe8bce3
PA
163 ft_tc: FileTransferTracker::new(),
164 ft_ts: FileTransferTracker::new(),
4aa80ac7 165 escaped: Vec::with_capacity(16),
1422b18a
PA
166 }
167 }
168
169 pub fn free(&mut self) {
922a453d 170 if !self.events.is_null() {
1422b18a
PA
171 core::sc_app_layer_decoder_events_free_events(&mut self.events);
172 }
922a453d 173 if !self.file_range.is_null() {
98f84d5a
PA
174 match unsafe { SC } {
175 None => panic!("BUG no suricata_config"),
176 Some(c) => {
177 //TODO get a file container instead of NULL
178 (c.HTPFileCloseHandleRange)(
179 std::ptr::null_mut(),
180 0,
181 self.file_range,
182 std::ptr::null_mut(),
183 0,
184 );
185 (c.HttpRangeFreeBlock)(self.file_range);
0caaf6bd 186 self.file_range = std::ptr::null_mut();
98f84d5a
PA
187 }
188 }
189 }
190 }
191
192 pub fn set_event(&mut self, event: HTTP2Event) {
193 let ev = event as u8;
194 core::sc_app_layer_decoder_events_set_event_raw(&mut self.events, ev);
1422b18a
PA
195 }
196
ee5b300c 197 fn handle_headers(&mut self, blocks: &Vec<parser::HTTP2FrameHeaderBlock>, dir: Direction) {
d8612282
PA
198 for i in 0..blocks.len() {
199 if blocks[i].name == "content-encoding".as_bytes().to_vec() {
200 self.decoder.http2_encoding_fromvec(&blocks[i].value, dir);
201 }
202 }
203 }
204
205 fn decompress<'a>(
ee5b300c
SB
206 &'a mut self, input: &'a [u8], dir: Direction, sfcm: &'static SuricataFileContext,
207 over: bool, files: &mut FileContainer, flags: u16, flow: *const Flow,
d8612282
PA
208 ) -> io::Result<()> {
209 let mut output = Vec::with_capacity(decompression::HTTP2_DECOMPRESSION_CHUNK_SIZE);
210 let decompressed = self.decoder.decompress(input, &mut output, dir)?;
211 let xid: u32 = self.tx_id as u32;
ee5b300c 212 if dir == Direction::ToClient {
bb98a18b
PA
213 self.ft_tc.tx_id = self.tx_id - 1;
214 if !self.ft_tc.file_open {
215 // we are now sure that new_chunk will open a file
216 // even if it may close it right afterwards
217 self.tx_data.incr_files_opened();
98f84d5a
PA
218 if let Ok(value) = detect::http2_frames_get_header_value_vec(
219 self,
ee5b300c 220 Direction::ToClient,
98f84d5a
PA
221 "content-range",
222 ) {
5bd065cb 223 match range::http2_parse_check_content_range(&value) {
98f84d5a
PA
224 Ok((_, v)) => {
225 range::http2_range_open(self, &v, flow, sfcm, flags, decompressed);
922a453d 226 if over && !self.file_range.is_null() {
98f84d5a
PA
227 range::http2_range_close(self, files, flags, &[])
228 }
229 }
230 _ => {
231 self.set_event(HTTP2Event::InvalidRange);
232 }
233 }
234 }
235 } else {
922a453d 236 if !self.file_range.is_null() {
98f84d5a
PA
237 if over {
238 range::http2_range_close(self, files, flags, decompressed)
239 } else {
240 range::http2_range_append(self.file_range, decompressed)
241 }
242 }
bb98a18b 243 }
6fe8bce3
PA
244 self.ft_tc.new_chunk(
245 sfcm,
246 files,
247 flags,
248 b"",
249 decompressed,
250 self.ft_tc.tracked, //offset = append
251 decompressed.len() as u32,
252 0,
253 over,
254 &xid,
255 );
256 } else {
bb98a18b
PA
257 self.ft_ts.tx_id = self.tx_id - 1;
258 if !self.ft_ts.file_open {
259 self.tx_data.incr_files_opened();
260 }
6fe8bce3
PA
261 self.ft_ts.new_chunk(
262 sfcm,
263 files,
264 flags,
265 b"",
266 decompressed,
267 self.ft_ts.tracked, //offset = append
268 decompressed.len() as u32,
269 0,
270 over,
271 &xid,
272 );
273 };
d8612282
PA
274 return Ok(());
275 }
276
1422b18a 277 fn handle_frame(
ee5b300c 278 &mut self, header: &parser::HTTP2FrameHeader, data: &HTTP2FrameTypeData, dir: Direction,
1422b18a
PA
279 ) {
280 //handle child_stream_id changes
281 match data {
282 HTTP2FrameTypeData::PUSHPROMISE(hs) => {
ee5b300c 283 if dir == Direction::ToClient {
1422b18a
PA
284 //we could set an event if self.child_stream_id != 0
285 if header.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS == 0 {
286 self.child_stream_id = hs.stream_id;
287 }
288 self.state = HTTP2TransactionState::HTTP2StateReserved;
289 }
d8612282 290 self.handle_headers(&hs.blocks, dir);
1422b18a 291 }
d8612282 292 HTTP2FrameTypeData::CONTINUATION(hs) => {
ee5b300c 293 if dir == Direction::ToClient
1422b18a
PA
294 && header.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS != 0
295 {
296 self.child_stream_id = 0;
297 }
d8612282 298 self.handle_headers(&hs.blocks, dir);
1422b18a 299 }
d8612282 300 HTTP2FrameTypeData::HEADERS(hs) => {
ee5b300c 301 if dir == Direction::ToClient {
1422b18a
PA
302 self.child_stream_id = 0;
303 }
d8612282 304 self.handle_headers(&hs.blocks, dir);
1422b18a
PA
305 }
306 HTTP2FrameTypeData::RSTSTREAM(_) => {
307 self.child_stream_id = 0;
308 }
309 _ => {}
310 }
311 //handle closing state changes
312 match data {
313 HTTP2FrameTypeData::HEADERS(_) | HTTP2FrameTypeData::DATA => {
314 if header.flags & parser::HTTP2_FLAG_HEADER_EOS != 0 {
315 match self.state {
b21acfbf
PA
316 HTTP2TransactionState::HTTP2StateHalfClosedClient
317 | HTTP2TransactionState::HTTP2StateDataServer => {
ee5b300c 318 if dir == Direction::ToClient {
1422b18a
PA
319 self.state = HTTP2TransactionState::HTTP2StateClosed;
320 }
321 }
322 HTTP2TransactionState::HTTP2StateHalfClosedServer => {
ee5b300c 323 if dir == Direction::ToServer {
1422b18a
PA
324 self.state = HTTP2TransactionState::HTTP2StateClosed;
325 }
326 }
b21acfbf 327 // do not revert back to a half closed state
1422b18a
PA
328 HTTP2TransactionState::HTTP2StateClosed => {}
329 HTTP2TransactionState::HTTP2StateGlobal => {}
330 _ => {
ee5b300c 331 if dir == Direction::ToClient {
1422b18a
PA
332 self.state = HTTP2TransactionState::HTTP2StateHalfClosedServer;
333 } else {
334 self.state = HTTP2TransactionState::HTTP2StateHalfClosedClient;
335 }
336 }
337 }
338 } else if header.ftype == parser::HTTP2FrameType::DATA as u8 {
339 //not end of stream
ee5b300c 340 if dir == Direction::ToServer {
b21acfbf
PA
341 if self.state < HTTP2TransactionState::HTTP2StateDataClient {
342 self.state = HTTP2TransactionState::HTTP2StateDataClient;
343 }
1422b18a 344 } else {
b21acfbf
PA
345 if self.state < HTTP2TransactionState::HTTP2StateDataServer {
346 self.state = HTTP2TransactionState::HTTP2StateDataServer;
347 }
1422b18a
PA
348 }
349 }
350 }
351 _ => {}
352 }
353 }
354}
355
356impl Drop for HTTP2Transaction {
357 fn drop(&mut self) {
358 self.free();
359 }
360}
361
cef2832d 362#[derive(AppLayerEvent)]
1422b18a 363pub enum HTTP2Event {
cef2832d 364 InvalidFrameHeader,
1422b18a
PA
365 InvalidClientMagic,
366 InvalidFrameData,
367 InvalidHeader,
368 InvalidFrameLength,
369 ExtraHeaderData,
370 LongFrameData,
371 StreamIdReuse,
6694737f 372 InvalidHTTP1Settings,
d8612282 373 FailedDecompression,
98f84d5a 374 InvalidRange,
1422b18a
PA
375}
376
c300a859
PA
377pub struct HTTP2DynTable {
378 pub table: Vec<parser::HTTP2FrameHeaderBlock>,
379 pub current_size: usize,
380 pub max_size: usize,
381 pub overflow: u8,
382}
383
384impl HTTP2DynTable {
385 pub fn new() -> Self {
386 Self {
387 table: Vec::with_capacity(64),
388 current_size: 0,
389 max_size: 4096, //default value
390 overflow: 0,
391 }
392 }
393}
394
1422b18a
PA
395pub struct HTTP2State {
396 tx_id: u64,
397 request_frame_size: u32,
398 response_frame_size: u32,
c300a859
PA
399 dynamic_headers_ts: HTTP2DynTable,
400 dynamic_headers_tc: HTTP2DynTable,
1422b18a
PA
401 transactions: Vec<HTTP2Transaction>,
402 progress: HTTP2ConnectionState,
5226ba1c 403 pub files: Files,
1422b18a
PA
404}
405
54e62ddf
JI
406impl State<HTTP2Transaction> for HTTP2State {
407 fn get_transactions(&self) -> &[HTTP2Transaction] {
408 &self.transactions
409 }
410}
411
1422b18a
PA
412impl HTTP2State {
413 pub fn new() -> Self {
414 Self {
415 tx_id: 0,
416 request_frame_size: 0,
417 response_frame_size: 0,
418 // the headers are encoded on one byte
419 // with a fixed number of static headers, and
420 // a variable number of dynamic headers
c300a859
PA
421 dynamic_headers_ts: HTTP2DynTable::new(),
422 dynamic_headers_tc: HTTP2DynTable::new(),
1422b18a
PA
423 transactions: Vec::new(),
424 progress: HTTP2ConnectionState::Http2StateInit,
3587033d 425 files: Files::default(),
1422b18a
PA
426 }
427 }
428
429 pub fn free(&mut self) {
0caaf6bd
PA
430 // this should be in HTTP2Transaction::free
431 // but we need state's file container cf https://redmine.openinfosecfoundation.org/issues/4444
432 for tx in &mut self.transactions {
433 if !tx.file_range.is_null() {
434 match unsafe { SC } {
435 None => panic!("BUG no suricata_config"),
436 Some(c) => {
437 (c.HTPFileCloseHandleRange)(
438 &mut self.files.files_tc,
439 0,
440 tx.file_range,
441 std::ptr::null_mut(),
442 0,
443 );
444 (c.HttpRangeFreeBlock)(tx.file_range);
445 tx.file_range = std::ptr::null_mut();
446 }
447 }
448 }
449 }
1422b18a 450 self.transactions.clear();
1422b18a
PA
451 }
452
6694737f 453 pub fn set_event(&mut self, event: HTTP2Event) {
1422b18a
PA
454 let len = self.transactions.len();
455 if len == 0 {
456 return;
457 }
458 let tx = &mut self.transactions[len - 1];
459 let ev = event as u8;
460 core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events, ev);
461 }
462
463 // Free a transaction by ID.
464 fn free_tx(&mut self, tx_id: u64) {
465 let len = self.transactions.len();
466 let mut found = false;
467 let mut index = 0;
468 for i in 0..len {
0caaf6bd 469 let tx = &mut self.transactions[i];
1422b18a
PA
470 if tx.tx_id == tx_id + 1 {
471 found = true;
472 index = i;
c0231168
PA
473 // this should be in HTTP2Transaction::free
474 // but we need state's file container cf https://redmine.openinfosecfoundation.org/issues/4444
475 if !tx.file_range.is_null() {
476 match unsafe { SC } {
477 None => panic!("BUG no suricata_config"),
478 Some(c) => {
479 (c.HTPFileCloseHandleRange)(
480 &mut self.files.files_tc,
481 0,
482 tx.file_range,
483 std::ptr::null_mut(),
484 0,
485 );
486 (c.HttpRangeFreeBlock)(tx.file_range);
0caaf6bd 487 tx.file_range = std::ptr::null_mut();
c0231168
PA
488 }
489 }
490 }
1422b18a
PA
491 break;
492 }
493 }
494 if found {
495 self.transactions.remove(index);
496 }
497 }
498
499 pub fn get_tx(&mut self, tx_id: u64) -> Option<&HTTP2Transaction> {
500 for tx in &mut self.transactions {
501 if tx.tx_id == tx_id + 1 {
502 return Some(tx);
503 }
504 }
505 return None;
506 }
507
f5746633 508 fn find_tx_index(&mut self, sid: u32) -> usize {
1422b18a
PA
509 for i in 0..self.transactions.len() {
510 //reverse order should be faster
511 let idx = self.transactions.len() - 1 - i;
512 if sid == self.transactions[idx].stream_id {
1422b18a
PA
513 return idx + 1;
514 }
515 }
516 return 0;
517 }
518
519 fn find_child_stream_id(&mut self, sid: u32) -> u32 {
520 for i in 0..self.transactions.len() {
521 //reverse order should be faster
522 if sid == self.transactions[self.transactions.len() - 1 - i].stream_id {
523 if self.transactions[self.transactions.len() - 1 - i].child_stream_id > 0 {
524 return self.transactions[self.transactions.len() - 1 - i].child_stream_id;
525 }
526 return sid;
527 }
528 }
529 return sid;
530 }
531
532 fn create_global_tx(&mut self) -> &mut HTTP2Transaction {
533 //special transaction with only one frame
534 //as it affects the global connection, there is no end to it
535 let mut tx = HTTP2Transaction::new();
536 self.tx_id += 1;
537 tx.tx_id = self.tx_id;
538 tx.state = HTTP2TransactionState::HTTP2StateGlobal;
539 self.transactions.push(tx);
540 return self.transactions.last_mut().unwrap();
541 }
542
7011bddf 543 pub fn find_or_create_tx(
ee5b300c 544 &mut self, header: &parser::HTTP2FrameHeader, data: &HTTP2FrameTypeData, dir: Direction,
1422b18a
PA
545 ) -> &mut HTTP2Transaction {
546 if header.stream_id == 0 {
547 return self.create_global_tx();
548 }
549 let sid = match data {
550 //yes, the right stream_id for Suricata is not the header one
551 HTTP2FrameTypeData::PUSHPROMISE(hs) => hs.stream_id,
552 HTTP2FrameTypeData::CONTINUATION(_) => {
ee5b300c 553 if dir == Direction::ToClient {
1422b18a
PA
554 //continuation of a push promise
555 self.find_child_stream_id(header.stream_id)
556 } else {
557 header.stream_id
558 }
559 }
560 _ => header.stream_id,
561 };
f5746633 562 let index = self.find_tx_index(sid);
1422b18a 563 if index > 0 {
f5746633
PA
564 if self.transactions[index - 1].state == HTTP2TransactionState::HTTP2StateClosed {
565 //these frames can be received in this state for a short period
566 if header.ftype != parser::HTTP2FrameType::RSTSTREAM as u8
567 && header.ftype != parser::HTTP2FrameType::WINDOWUPDATE as u8
568 && header.ftype != parser::HTTP2FrameType::PRIORITY as u8
569 {
570 self.set_event(HTTP2Event::StreamIdReuse);
571 }
572 }
1422b18a
PA
573 return &mut self.transactions[index - 1];
574 } else {
575 let mut tx = HTTP2Transaction::new();
576 self.tx_id += 1;
577 tx.tx_id = self.tx_id;
578 tx.stream_id = sid;
579 tx.state = HTTP2TransactionState::HTTP2StateOpen;
580 self.transactions.push(tx);
581 return self.transactions.last_mut().unwrap();
582 }
583 }
584
ee5b300c 585 fn process_headers(&mut self, blocks: &Vec<parser::HTTP2FrameHeaderBlock>, dir: Direction) {
a63ee5ad
PA
586 let (mut update, mut sizeup) = (false, 0);
587 for i in 0..blocks.len() {
588 if blocks[i].error >= parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeError {
589 self.set_event(HTTP2Event::InvalidHeader);
590 } else if blocks[i].error
591 == parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate
592 {
593 update = true;
594 if blocks[i].sizeupdate > sizeup {
595 sizeup = blocks[i].sizeupdate;
596 }
597 }
598 }
599 if update {
600 //borrow checker forbids to pass directly dyn_headers
ee5b300c 601 let dyn_headers = if dir == Direction::ToClient {
a63ee5ad
PA
602 &mut self.dynamic_headers_tc
603 } else {
604 &mut self.dynamic_headers_ts
605 };
606 dyn_headers.max_size = sizeup as usize;
607 }
608 }
609
1422b18a 610 fn parse_frame_data(
ee5b300c 611 &mut self, ftype: u8, input: &[u8], complete: bool, hflags: u8, dir: Direction,
1422b18a
PA
612 ) -> HTTP2FrameTypeData {
613 match num::FromPrimitive::from_u8(ftype) {
614 Some(parser::HTTP2FrameType::GOAWAY) => {
615 if input.len() < HTTP2_FRAME_GOAWAY_LEN {
616 self.set_event(HTTP2Event::InvalidFrameLength);
617 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
618 reason: HTTP2FrameUnhandledReason::Incomplete,
619 });
620 }
621 match parser::http2_parse_frame_goaway(input) {
622 Ok((_, goaway)) => {
623 return HTTP2FrameTypeData::GOAWAY(goaway);
624 }
625 Err(_) => {
626 self.set_event(HTTP2Event::InvalidFrameData);
627 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
628 reason: HTTP2FrameUnhandledReason::ParsingError,
629 });
630 }
631 }
632 }
633 Some(parser::HTTP2FrameType::SETTINGS) => {
634 match parser::http2_parse_frame_settings(input) {
635 Ok((_, set)) => {
c300a859
PA
636 for i in 0..set.len() {
637 if set[i].id == parser::HTTP2SettingsId::SETTINGSHEADERTABLESIZE {
1fd6f5bc 638 //reverse order as this is what we accept from the other endpoint
ee5b300c 639 let dyn_headers = if dir == Direction::ToClient {
1fd6f5bc
PA
640 &mut self.dynamic_headers_ts
641 } else {
642 &mut self.dynamic_headers_tc
643 };
644 dyn_headers.max_size = set[i].value as usize;
c300a859
PA
645 if set[i].value > HTTP2_MAX_TABLESIZE {
646 //mark potential overflow
1fd6f5bc 647 dyn_headers.overflow = 1;
c300a859
PA
648 } else {
649 //reset in case peer set a lower value, to be tested
1fd6f5bc 650 dyn_headers.overflow = 0;
c300a859
PA
651 }
652 }
653 }
1422b18a
PA
654 //we could set an event on remaining data
655 return HTTP2FrameTypeData::SETTINGS(set);
656 }
657 Err(nom::Err::Incomplete(_)) => {
658 if complete {
659 self.set_event(HTTP2Event::InvalidFrameData);
660 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
661 reason: HTTP2FrameUnhandledReason::ParsingError,
662 });
663 } else {
664 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
665 reason: HTTP2FrameUnhandledReason::TooLong,
666 });
667 }
668 }
669 Err(_) => {
670 self.set_event(HTTP2Event::InvalidFrameData);
671 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
672 reason: HTTP2FrameUnhandledReason::ParsingError,
673 });
674 }
675 }
676 }
677 Some(parser::HTTP2FrameType::RSTSTREAM) => {
678 if input.len() != HTTP2_FRAME_RSTSTREAM_LEN {
679 self.set_event(HTTP2Event::InvalidFrameLength);
680 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
681 reason: HTTP2FrameUnhandledReason::Incomplete,
682 });
683 } else {
684 match parser::http2_parse_frame_rststream(input) {
685 Ok((_, rst)) => {
686 return HTTP2FrameTypeData::RSTSTREAM(rst);
687 }
688 Err(_) => {
689 self.set_event(HTTP2Event::InvalidFrameData);
690 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
691 reason: HTTP2FrameUnhandledReason::ParsingError,
692 });
693 }
694 }
695 }
696 }
697 Some(parser::HTTP2FrameType::PRIORITY) => {
698 if input.len() != HTTP2_FRAME_PRIORITY_LEN {
699 self.set_event(HTTP2Event::InvalidFrameLength);
700 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
701 reason: HTTP2FrameUnhandledReason::Incomplete,
702 });
703 } else {
704 match parser::http2_parse_frame_priority(input) {
705 Ok((_, priority)) => {
706 return HTTP2FrameTypeData::PRIORITY(priority);
707 }
708 Err(_) => {
709 self.set_event(HTTP2Event::InvalidFrameData);
710 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
711 reason: HTTP2FrameUnhandledReason::ParsingError,
712 });
713 }
714 }
715 }
716 }
717 Some(parser::HTTP2FrameType::WINDOWUPDATE) => {
718 if input.len() != HTTP2_FRAME_WINDOWUPDATE_LEN {
719 self.set_event(HTTP2Event::InvalidFrameLength);
720 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
721 reason: HTTP2FrameUnhandledReason::Incomplete,
722 });
723 } else {
724 match parser::http2_parse_frame_windowupdate(input) {
725 Ok((_, wu)) => {
726 return HTTP2FrameTypeData::WINDOWUPDATE(wu);
727 }
728 Err(_) => {
729 self.set_event(HTTP2Event::InvalidFrameData);
730 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
731 reason: HTTP2FrameUnhandledReason::ParsingError,
732 });
733 }
734 }
735 }
736 }
737 Some(parser::HTTP2FrameType::PUSHPROMISE) => {
ee5b300c 738 let dyn_headers = if dir == Direction::ToClient {
1422b18a
PA
739 &mut self.dynamic_headers_tc
740 } else {
741 &mut self.dynamic_headers_ts
742 };
743 match parser::http2_parse_frame_push_promise(input, hflags, dyn_headers) {
744 Ok((_, hs)) => {
a63ee5ad 745 self.process_headers(&hs.blocks, dir);
1422b18a
PA
746 return HTTP2FrameTypeData::PUSHPROMISE(hs);
747 }
748 Err(nom::Err::Incomplete(_)) => {
749 if complete {
750 self.set_event(HTTP2Event::InvalidFrameData);
751 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
752 reason: HTTP2FrameUnhandledReason::ParsingError,
753 });
754 } else {
755 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
756 reason: HTTP2FrameUnhandledReason::TooLong,
757 });
758 }
759 }
760 Err(_) => {
761 self.set_event(HTTP2Event::InvalidFrameData);
762 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
763 reason: HTTP2FrameUnhandledReason::ParsingError,
764 });
765 }
766 }
767 }
768 Some(parser::HTTP2FrameType::DATA) => {
769 return HTTP2FrameTypeData::DATA;
770 }
771 Some(parser::HTTP2FrameType::CONTINUATION) => {
ee5b300c 772 let dyn_headers = if dir == Direction::ToClient {
1422b18a
PA
773 &mut self.dynamic_headers_tc
774 } else {
775 &mut self.dynamic_headers_ts
776 };
777 match parser::http2_parse_frame_continuation(input, dyn_headers) {
778 Ok((_, hs)) => {
a63ee5ad 779 self.process_headers(&hs.blocks, dir);
1422b18a
PA
780 return HTTP2FrameTypeData::CONTINUATION(hs);
781 }
782 Err(nom::Err::Incomplete(_)) => {
783 if complete {
784 self.set_event(HTTP2Event::InvalidFrameData);
785 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
786 reason: HTTP2FrameUnhandledReason::ParsingError,
787 });
788 } else {
789 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
790 reason: HTTP2FrameUnhandledReason::TooLong,
791 });
792 }
793 }
794 Err(_) => {
795 self.set_event(HTTP2Event::InvalidFrameData);
796 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
797 reason: HTTP2FrameUnhandledReason::ParsingError,
798 });
799 }
800 }
801 }
802 Some(parser::HTTP2FrameType::HEADERS) => {
ee5b300c 803 let dyn_headers = if dir == Direction::ToClient {
1422b18a
PA
804 &mut self.dynamic_headers_tc
805 } else {
806 &mut self.dynamic_headers_ts
807 };
808 match parser::http2_parse_frame_headers(input, hflags, dyn_headers) {
809 Ok((hrem, hs)) => {
a63ee5ad 810 self.process_headers(&hs.blocks, dir);
1422b18a
PA
811 if hrem.len() > 0 {
812 SCLogDebug!("Remaining data for HTTP2 headers");
813 self.set_event(HTTP2Event::ExtraHeaderData);
814 }
815 return HTTP2FrameTypeData::HEADERS(hs);
816 }
817 Err(nom::Err::Incomplete(_)) => {
818 if complete {
819 self.set_event(HTTP2Event::InvalidFrameData);
820 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
821 reason: HTTP2FrameUnhandledReason::ParsingError,
822 });
823 } else {
824 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
825 reason: HTTP2FrameUnhandledReason::TooLong,
826 });
827 }
828 }
829 Err(_) => {
830 self.set_event(HTTP2Event::InvalidFrameData);
831 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
832 reason: HTTP2FrameUnhandledReason::ParsingError,
833 });
834 }
835 }
836 }
837 Some(parser::HTTP2FrameType::PING) => {
838 return HTTP2FrameTypeData::PING;
839 }
840 _ => {
841 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
842 reason: HTTP2FrameUnhandledReason::UnknownType,
843 });
844 }
845 }
846 }
847
98f84d5a 848 fn parse_frames(
ee5b300c 849 &mut self, mut input: &[u8], il: usize, dir: Direction, flow: *const Flow,
98f84d5a 850 ) -> AppLayerResult {
1422b18a
PA
851 while input.len() > 0 {
852 match parser::http2_parse_frame_header(input) {
853 Ok((rem, head)) => {
854 let hl = head.length as usize;
855
856 //we check for completeness first
857 if rem.len() < hl {
858 //but limit ourselves so as not to exhaust memory
859 if hl < HTTP2_MAX_HANDLED_FRAME_SIZE {
860 return AppLayerResult::incomplete(
861 (il - input.len()) as u32,
862 (HTTP2_FRAME_HEADER_LEN + hl) as u32,
863 );
864 } else if rem.len() < HTTP2_MIN_HANDLED_FRAME_SIZE {
865 return AppLayerResult::incomplete(
866 (il - input.len()) as u32,
867 (HTTP2_FRAME_HEADER_LEN + HTTP2_MIN_HANDLED_FRAME_SIZE) as u32,
868 );
869 } else {
870 self.set_event(HTTP2Event::LongFrameData);
871 self.request_frame_size = head.length - (rem.len() as u32);
872 }
873 }
874
875 //get a safe length for the buffer
876 let (hlsafe, complete) = if rem.len() < hl {
877 (rem.len(), false)
878 } else {
879 (hl, true)
880 };
881
882 if head.length == 0 && head.ftype == parser::HTTP2FrameType::SETTINGS as u8 {
883 input = &rem[hlsafe..];
884 continue;
885 }
886 let txdata = self.parse_frame_data(
887 head.ftype,
888 &rem[..hlsafe],
889 complete,
890 head.flags,
891 dir,
892 );
893
894 let tx = self.find_or_create_tx(&head, &txdata, dir);
895 tx.handle_frame(&head, &txdata, dir);
896 let over = head.flags & parser::HTTP2_FLAG_HEADER_EOS != 0;
1422b18a 897 let ftype = head.ftype;
f5746633 898 let sid = head.stream_id;
ee5b300c 899 if dir == Direction::ToServer {
1422b18a
PA
900 tx.frames_ts.push(HTTP2Frame {
901 header: head,
902 data: txdata,
903 });
904 } else {
905 tx.frames_tc.push(HTTP2Frame {
906 header: head,
907 data: txdata,
908 });
909 }
910 if ftype == parser::HTTP2FrameType::DATA as u8 {
f5746633
PA
911 match unsafe { SURICATA_HTTP2_FILE_CONFIG } {
912 Some(sfcm) => {
913 //borrow checker forbids to reuse directly tx
914 let index = self.find_tx_index(sid);
915 if index > 0 {
bb98a18b 916 let tx_same = &mut self.transactions[index - 1];
ee5b300c 917 let (files, flags) = self.files.get(dir);
d8612282
PA
918 match tx_same.decompress(
919 &rem[..hlsafe],
920 dir,
f5746633 921 sfcm,
d8612282 922 over,
f5746633
PA
923 files,
924 flags,
98f84d5a 925 flow,
d8612282
PA
926 ) {
927 Err(_e) => {
928 self.set_event(HTTP2Event::FailedDecompression);
929 }
bb98a18b 930 _ => {}
d8612282 931 }
f5746633
PA
932 }
933 }
aee8e601 934 None => panic!("no SURICATA_HTTP2_FILE_CONFIG"),
f5746633 935 }
1422b18a
PA
936 }
937 input = &rem[hlsafe..];
938 }
939 Err(nom::Err::Incomplete(_)) => {
940 //we may have consumed data from previous records
941 return AppLayerResult::incomplete(
942 (il - input.len()) as u32,
943 HTTP2_FRAME_HEADER_LEN as u32,
944 );
945 }
946 Err(_) => {
947 self.set_event(HTTP2Event::InvalidFrameHeader);
948 return AppLayerResult::err();
949 }
950 }
951 }
952 return AppLayerResult::ok();
953 }
954
98f84d5a 955 fn parse_ts(&mut self, mut input: &[u8], flow: *const Flow) -> AppLayerResult {
1422b18a 956 //very first : skip magic
1a88df7e 957 let mut magic_consumed = 0;
1422b18a
PA
958 if self.progress < HTTP2ConnectionState::Http2StateMagicDone {
959 //skip magic
960 if input.len() >= HTTP2_MAGIC_LEN {
961 //skip magic
962 match std::str::from_utf8(&input[..HTTP2_MAGIC_LEN]) {
963 Ok("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n") => {
964 input = &input[HTTP2_MAGIC_LEN..];
1a88df7e 965 magic_consumed = HTTP2_MAGIC_LEN;
1422b18a
PA
966 }
967 Ok(&_) => {
968 self.set_event(HTTP2Event::InvalidClientMagic);
969 }
970 Err(_) => {
971 return AppLayerResult::err();
972 }
973 }
974 self.progress = HTTP2ConnectionState::Http2StateMagicDone;
975 } else {
976 //still more buffer
977 return AppLayerResult::incomplete(0 as u32, HTTP2_MAGIC_LEN as u32);
978 }
979 }
980 //first consume frame bytes
981 let il = input.len();
982 if self.request_frame_size > 0 {
983 let ilen = input.len() as u32;
984 if self.request_frame_size >= ilen {
985 self.request_frame_size -= ilen;
986 return AppLayerResult::ok();
987 } else {
988 let start = self.request_frame_size as usize;
989 input = &input[start..];
990 self.request_frame_size = 0;
991 }
992 }
993
994 //then parse all we can
ee5b300c 995 let r = self.parse_frames(input, il, Direction::ToServer, flow);
1a88df7e
PA
996 if r.status == 1 {
997 //adds bytes consumed by banner to incomplete result
998 return AppLayerResult::incomplete(r.consumed + magic_consumed as u32, r.needed);
999 } else {
1000 return r;
1001 }
1422b18a
PA
1002 }
1003
98f84d5a 1004 fn parse_tc(&mut self, mut input: &[u8], flow: *const Flow) -> AppLayerResult {
1422b18a
PA
1005 //first consume frame bytes
1006 let il = input.len();
1007 if self.response_frame_size > 0 {
1008 let ilen = input.len() as u32;
1009 if self.response_frame_size >= ilen {
1010 self.response_frame_size -= ilen;
1011 return AppLayerResult::ok();
1012 } else {
1013 let start = self.response_frame_size as usize;
1014 input = &input[start..];
1015 self.response_frame_size = 0;
1016 }
1017 }
1018 //then parse all we can
ee5b300c 1019 return self.parse_frames(input, il, Direction::ToClient, flow);
1422b18a 1020 }
1422b18a
PA
1021}
1022
1023// C exports.
1024
1422b18a
PA
1025export_tx_data_get!(rs_http2_get_tx_data, HTTP2Transaction);
1026
1422b18a
PA
1027/// C entry point for a probing parser.
1028#[no_mangle]
363b5f99 1029pub unsafe extern "C" fn rs_http2_probing_parser_tc(
1422b18a
PA
1030 _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8,
1031) -> AppProto {
922a453d 1032 if !input.is_null() {
1422b18a
PA
1033 let slice = build_slice!(input, input_len as usize);
1034 match parser::http2_parse_frame_header(slice) {
1035 Ok((_, header)) => {
1036 if header.reserved != 0
1037 || header.length > HTTP2_DEFAULT_MAX_FRAME_SIZE
1038 || header.flags & 0xFE != 0
1039 || header.ftype != parser::HTTP2FrameType::SETTINGS as u8
1040 {
363b5f99 1041 return ALPROTO_FAILED;
1422b18a 1042 }
363b5f99 1043 return ALPROTO_HTTP2;
1422b18a
PA
1044 }
1045 Err(nom::Err::Incomplete(_)) => {
1046 return ALPROTO_UNKNOWN;
1047 }
1048 Err(_) => {
bb98a18b 1049 return ALPROTO_FAILED;
1422b18a
PA
1050 }
1051 }
1052 }
1053 return ALPROTO_UNKNOWN;
1054}
1055
7011bddf
PA
1056/// Extern functions operating on HTTP2.
1057extern "C" {
1058 pub fn HTTP2MimicHttp1Request(
1059 orig_state: *mut std::os::raw::c_void, new_state: *mut std::os::raw::c_void,
1060 );
1061}
1062
363b5f99
JI
1063// Suppress the unsafe warning here as creating a state for an app-layer
1064// is typically not unsafe.
1422b18a 1065#[no_mangle]
363b5f99 1066#[allow(clippy::not_unsafe_ptr_arg_deref)]
7011bddf
PA
1067pub extern "C" fn rs_http2_state_new(
1068 orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto,
1069) -> *mut std::os::raw::c_void {
1422b18a
PA
1070 let state = HTTP2State::new();
1071 let boxed = Box::new(state);
53413f2d 1072 let r = Box::into_raw(boxed) as *mut _;
922a453d 1073 if !orig_state.is_null() {
707f0272 1074 //we could check ALPROTO_HTTP1 == orig_proto
7011bddf
PA
1075 unsafe {
1076 HTTP2MimicHttp1Request(orig_state, r);
1077 }
1078 }
1079 return r;
1422b18a
PA
1080}
1081
1082#[no_mangle]
363b5f99
JI
1083pub unsafe extern "C" fn rs_http2_state_free(state: *mut std::os::raw::c_void) {
1084 let mut state: Box<HTTP2State> = Box::from_raw(state as _);
1422b18a
PA
1085 state.free();
1086}
1087
1088#[no_mangle]
363b5f99 1089pub unsafe extern "C" fn rs_http2_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) {
1422b18a
PA
1090 let state = cast_pointer!(state, HTTP2State);
1091 state.free_tx(tx_id);
1092}
1093
1094#[no_mangle]
363b5f99 1095pub unsafe extern "C" fn rs_http2_parse_ts(
1422b18a
PA
1096 flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void,
1097 input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8,
1098) -> AppLayerResult {
1099 let state = cast_pointer!(state, HTTP2State);
1100 let buf = build_slice!(input, input_len as usize);
1101
ee5b300c 1102 state.files.flags_ts = FileFlowToFlags(flow, Direction::ToServer.into());
f5746633 1103 state.files.flags_ts = state.files.flags_ts | FILE_USE_DETECT;
98f84d5a 1104 return state.parse_ts(buf, flow);
1422b18a
PA
1105}
1106
1107#[no_mangle]
363b5f99 1108pub unsafe extern "C" fn rs_http2_parse_tc(
1422b18a
PA
1109 flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void,
1110 input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8,
1111) -> AppLayerResult {
1112 let state = cast_pointer!(state, HTTP2State);
1113 let buf = build_slice!(input, input_len as usize);
ee5b300c 1114 state.files.flags_tc = FileFlowToFlags(flow, Direction::ToClient.into());
f5746633 1115 state.files.flags_tc = state.files.flags_tc | FILE_USE_DETECT;
98f84d5a 1116 return state.parse_tc(buf, flow);
1422b18a
PA
1117}
1118
1119#[no_mangle]
363b5f99 1120pub unsafe extern "C" fn rs_http2_state_get_tx(
1422b18a
PA
1121 state: *mut std::os::raw::c_void, tx_id: u64,
1122) -> *mut std::os::raw::c_void {
1123 let state = cast_pointer!(state, HTTP2State);
1124 match state.get_tx(tx_id) {
1125 Some(tx) => {
53413f2d 1126 return tx as *const _ as *mut _;
1422b18a
PA
1127 }
1128 None => {
1129 return std::ptr::null_mut();
1130 }
1131 }
1132}
1133
1134#[no_mangle]
363b5f99 1135pub unsafe extern "C" fn rs_http2_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 {
1422b18a
PA
1136 let state = cast_pointer!(state, HTTP2State);
1137 return state.tx_id;
1138}
1139
1422b18a 1140#[no_mangle]
bb98a18b
PA
1141pub unsafe extern "C" fn rs_http2_tx_get_state(
1142 tx: *mut std::os::raw::c_void,
1143) -> HTTP2TransactionState {
1422b18a
PA
1144 let tx = cast_pointer!(tx, HTTP2Transaction);
1145 return tx.state;
1146}
1147
1148#[no_mangle]
363b5f99 1149pub unsafe extern "C" fn rs_http2_tx_get_alstate_progress(
1422b18a
PA
1150 tx: *mut std::os::raw::c_void, _direction: u8,
1151) -> std::os::raw::c_int {
1152 return rs_http2_tx_get_state(tx) as i32;
1153}
1154
1155#[no_mangle]
363b5f99 1156pub unsafe extern "C" fn rs_http2_state_get_events(
1422b18a
PA
1157 tx: *mut std::os::raw::c_void,
1158) -> *mut core::AppLayerDecoderEvents {
1159 let tx = cast_pointer!(tx, HTTP2Transaction);
1160 return tx.events;
1161}
1162
1422b18a 1163#[no_mangle]
363b5f99 1164pub unsafe extern "C" fn rs_http2_getfiles(
1422b18a
PA
1165 state: *mut std::os::raw::c_void, direction: u8,
1166) -> *mut FileContainer {
1167 let state = cast_pointer!(state, HTTP2State);
ee5b300c 1168 if direction == Direction::ToClient.into() {
1422b18a
PA
1169 &mut state.files.files_tc as *mut FileContainer
1170 } else {
1171 &mut state.files.files_ts as *mut FileContainer
1172 }
1173}
1174
1175// Parser name as a C style string.
1176const PARSER_NAME: &'static [u8] = b"http2\0";
1177
1178#[no_mangle]
1179pub unsafe extern "C" fn rs_http2_register_parser() {
9d1b030f 1180 let default_port = CString::new("[80]").unwrap();
1422b18a
PA
1181 let parser = RustParser {
1182 name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
1183 default_port: default_port.as_ptr(),
1184 ipproto: IPPROTO_TCP,
1185 probe_ts: None, // big magic string should be enough
1186 probe_tc: Some(rs_http2_probing_parser_tc),
1187 min_depth: HTTP2_FRAME_HEADER_LEN as u16,
1188 max_depth: HTTP2_MAGIC_LEN as u16,
1189 state_new: rs_http2_state_new,
1190 state_free: rs_http2_state_free,
1191 tx_free: rs_http2_state_tx_free,
1192 parse_ts: rs_http2_parse_ts,
1193 parse_tc: rs_http2_parse_tc,
1194 get_tx_count: rs_http2_state_get_tx_count,
1195 get_tx: rs_http2_state_get_tx,
efc9a7a3
VJ
1196 tx_comp_st_ts: HTTP2TransactionState::HTTP2StateClosed as i32,
1197 tx_comp_st_tc: HTTP2TransactionState::HTTP2StateClosed as i32,
1422b18a 1198 tx_get_progress: rs_http2_tx_get_alstate_progress,
1422b18a 1199 get_events: Some(rs_http2_state_get_events),
cef2832d
JI
1200 get_eventinfo: Some(HTTP2Event::get_event_info),
1201 get_eventinfo_byid: Some(HTTP2Event::get_event_info_by_id),
1422b18a
PA
1202 localstorage_new: None,
1203 localstorage_free: None,
1204 get_files: Some(rs_http2_getfiles),
54e62ddf 1205 get_tx_iterator: Some(applayer::state_get_tx_iterator::<HTTP2State, HTTP2Transaction>),
1422b18a
PA
1206 get_tx_data: rs_http2_get_tx_data,
1207 apply_tx_config: None,
1208 flags: 0,
4da0d9bd 1209 truncate: None,
1422b18a
PA
1210 };
1211
1212 let ip_proto_str = CString::new("tcp").unwrap();
1213
1214 if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
1215 let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
1216 ALPROTO_HTTP2 = alproto;
1217 if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
1218 let _ = AppLayerRegisterParser(&parser, alproto);
1219 }
1220 SCLogDebug!("Rust http2 parser registered.");
1221 } else {
1222 SCLogNotice!("Protocol detector and parser disabled for HTTP2.");
1223 }
1224}