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