1 /* Copyright (C) 2020 Open Information Security Foundation
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
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.
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
19 use crate::applayer::{self, *};
21 self, AppProto, Flow, SuricataFileContext, ALPROTO_FAILED, ALPROTO_UNKNOWN, IPPROTO_TCP,
22 STREAM_TOCLIENT, STREAM_TOSERVER,
24 use crate::filecontainer::*;
25 use crate::filetracker::*;
28 use std::ffi::{CStr, CString};
30 use std::mem::transmute;
32 static mut ALPROTO_HTTP2: AppProto = ALPROTO_UNKNOWN;
34 const HTTP2_DEFAULT_MAX_FRAME_SIZE: u32 = 16384;
35 const HTTP2_MAX_HANDLED_FRAME_SIZE: usize = 65536;
36 const HTTP2_MIN_HANDLED_FRAME_SIZE: usize = 256;
38 pub static mut SURICATA_HTTP2_FILE_CONFIG: Option<&'static SuricataFileContext> = None;
41 pub extern "C" fn rs_http2_init(context: &'static mut SuricataFileContext) {
43 SURICATA_HTTP2_FILE_CONFIG = Some(context);
48 #[derive(Copy, Clone, PartialOrd, PartialEq)]
49 pub enum HTTP2ConnectionState {
51 Http2StateMagicDone = 1,
54 const HTTP2_FRAME_HEADER_LEN: usize = 9;
55 const HTTP2_MAGIC_LEN: usize = 24;
56 const HTTP2_FRAME_GOAWAY_LEN: usize = 4;
57 const HTTP2_FRAME_RSTSTREAM_LEN: usize = 4;
58 const HTTP2_FRAME_PRIORITY_LEN: usize = 5;
59 const HTTP2_FRAME_WINDOWUPDATE_LEN: usize = 4;
60 //TODO make this configurable
61 pub const HTTP2_MAX_TABLESIZE: u32 = 0x10000; // 65536
64 #[derive(Copy, Clone, PartialOrd, PartialEq, Debug)]
65 pub enum HTTP2FrameUnhandledReason {
72 impl fmt::Display for HTTP2FrameUnhandledReason {
73 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74 write!(f, "{:?}", self)
79 pub struct HTTP2FrameUnhandled {
80 pub reason: HTTP2FrameUnhandledReason,
83 pub enum HTTP2FrameTypeData {
84 PRIORITY(parser::HTTP2FramePriority),
85 GOAWAY(parser::HTTP2FrameGoAway),
86 RSTSTREAM(parser::HTTP2FrameRstStream),
87 SETTINGS(Vec<parser::HTTP2FrameSettings>),
88 WINDOWUPDATE(parser::HTTP2FrameWindowUpdate),
89 HEADERS(parser::HTTP2FrameHeaders),
90 PUSHPROMISE(parser::HTTP2FramePushPromise),
91 CONTINUATION(parser::HTTP2FrameContinuation),
95 UNHANDLED(HTTP2FrameUnhandled),
99 #[derive(Copy, Clone, PartialOrd, PartialEq, Debug)]
100 pub enum HTTP2TransactionState {
103 HTTP2StateReserved = 2,
104 HTTP2StateDataClient = 3,
105 HTTP2StateHalfClosedClient = 4,
106 HTTP2StateDataServer = 5,
107 HTTP2StateHalfClosedServer = 6,
108 HTTP2StateClosed = 7,
109 //not a RFC-defined state, used for stream 0 frames appyling to the global connection
110 HTTP2StateGlobal = 8,
113 pub struct HTTP2Frame {
114 pub header: parser::HTTP2FrameHeader,
115 pub data: HTTP2FrameTypeData,
118 pub struct HTTP2Transaction {
121 pub state: HTTP2TransactionState,
122 child_stream_id: u32,
124 pub frames_tc: Vec<HTTP2Frame>,
125 pub frames_ts: Vec<HTTP2Frame>,
127 de_state: Option<*mut core::DetectEngineState>,
128 events: *mut core::AppLayerDecoderEvents,
129 tx_data: AppLayerTxData,
130 ft: FileTransferTracker,
132 //temporary escaped header for detection
133 //must be attached to transaction for memory management (be freed at the right time)
134 pub escaped: Vec<Vec<u8>>,
137 impl HTTP2Transaction {
138 pub fn new() -> HTTP2Transaction {
143 state: HTTP2TransactionState::HTTP2StateIdle,
144 frames_tc: Vec::new(),
145 frames_ts: Vec::new(),
147 events: std::ptr::null_mut(),
148 tx_data: AppLayerTxData::new(),
149 ft: FileTransferTracker::new(),
150 escaped: Vec::with_capacity(16),
154 pub fn free(&mut self) {
155 if self.events != std::ptr::null_mut() {
156 core::sc_app_layer_decoder_events_free_events(&mut self.events);
158 if let Some(state) = self.de_state {
159 core::sc_detect_engine_state_free(state);
164 &mut self, header: &parser::HTTP2FrameHeader, data: &HTTP2FrameTypeData, dir: u8,
166 //handle child_stream_id changes
168 HTTP2FrameTypeData::PUSHPROMISE(hs) => {
169 if dir == STREAM_TOCLIENT {
170 //we could set an event if self.child_stream_id != 0
171 if header.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS == 0 {
172 self.child_stream_id = hs.stream_id;
174 self.state = HTTP2TransactionState::HTTP2StateReserved;
177 HTTP2FrameTypeData::CONTINUATION(_) => {
178 if dir == STREAM_TOCLIENT
179 && header.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS != 0
181 self.child_stream_id = 0;
184 HTTP2FrameTypeData::HEADERS(_) => {
185 if dir == STREAM_TOCLIENT {
186 self.child_stream_id = 0;
189 HTTP2FrameTypeData::RSTSTREAM(_) => {
190 self.child_stream_id = 0;
194 //handle closing state changes
196 HTTP2FrameTypeData::HEADERS(_) | HTTP2FrameTypeData::DATA => {
197 if header.flags & parser::HTTP2_FLAG_HEADER_EOS != 0 {
199 HTTP2TransactionState::HTTP2StateHalfClosedClient
200 | HTTP2TransactionState::HTTP2StateDataServer => {
201 if dir == STREAM_TOCLIENT {
202 self.state = HTTP2TransactionState::HTTP2StateClosed;
205 HTTP2TransactionState::HTTP2StateHalfClosedServer => {
206 if dir == STREAM_TOSERVER {
207 self.state = HTTP2TransactionState::HTTP2StateClosed;
210 // do not revert back to a half closed state
211 HTTP2TransactionState::HTTP2StateClosed => {}
212 HTTP2TransactionState::HTTP2StateGlobal => {}
214 if dir == STREAM_TOCLIENT {
215 self.state = HTTP2TransactionState::HTTP2StateHalfClosedServer;
217 self.state = HTTP2TransactionState::HTTP2StateHalfClosedClient;
221 } else if header.ftype == parser::HTTP2FrameType::DATA as u8 {
223 if dir == STREAM_TOSERVER {
224 if self.state < HTTP2TransactionState::HTTP2StateDataClient {
225 self.state = HTTP2TransactionState::HTTP2StateDataClient;
228 if self.state < HTTP2TransactionState::HTTP2StateDataServer {
229 self.state = HTTP2TransactionState::HTTP2StateDataServer;
239 impl Drop for HTTP2Transaction {
246 pub enum HTTP2Event {
247 InvalidFrameHeader = 0,
255 InvalidHTTP1Settings,
259 fn from_i32(value: i32) -> Option<HTTP2Event> {
261 0 => Some(HTTP2Event::InvalidFrameHeader),
262 1 => Some(HTTP2Event::InvalidClientMagic),
263 2 => Some(HTTP2Event::InvalidFrameData),
264 3 => Some(HTTP2Event::InvalidHeader),
265 4 => Some(HTTP2Event::InvalidFrameLength),
266 5 => Some(HTTP2Event::ExtraHeaderData),
267 6 => Some(HTTP2Event::LongFrameData),
268 7 => Some(HTTP2Event::StreamIdReuse),
269 8 => Some(HTTP2Event::InvalidHTTP1Settings),
275 pub struct HTTP2DynTable {
276 pub table: Vec<parser::HTTP2FrameHeaderBlock>,
277 pub current_size: usize,
283 pub fn new() -> Self {
285 table: Vec::with_capacity(64),
287 max_size: 4096, //default value
293 pub struct HTTP2State {
295 request_frame_size: u32,
296 response_frame_size: u32,
297 dynamic_headers_ts: HTTP2DynTable,
298 dynamic_headers_tc: HTTP2DynTable,
299 transactions: Vec<HTTP2Transaction>,
300 progress: HTTP2ConnectionState,
305 pub fn new() -> Self {
308 request_frame_size: 0,
309 response_frame_size: 0,
310 // the headers are encoded on one byte
311 // with a fixed number of static headers, and
312 // a variable number of dynamic headers
313 dynamic_headers_ts: HTTP2DynTable::new(),
314 dynamic_headers_tc: HTTP2DynTable::new(),
315 transactions: Vec::new(),
316 progress: HTTP2ConnectionState::Http2StateInit,
321 pub fn free(&mut self) {
322 self.transactions.clear();
326 pub fn set_event(&mut self, event: HTTP2Event) {
327 let len = self.transactions.len();
331 let tx = &mut self.transactions[len - 1];
332 let ev = event as u8;
333 core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events, ev);
336 // Free a transaction by ID.
337 fn free_tx(&mut self, tx_id: u64) {
338 let len = self.transactions.len();
339 let mut found = false;
342 let tx = &self.transactions[i];
343 if tx.tx_id == tx_id + 1 {
350 self.transactions.remove(index);
354 pub fn get_tx(&mut self, tx_id: u64) -> Option<&HTTP2Transaction> {
355 for tx in &mut self.transactions {
356 if tx.tx_id == tx_id + 1 {
363 fn find_tx_index(&mut self, sid: u32) -> usize {
364 for i in 0..self.transactions.len() {
365 //reverse order should be faster
366 let idx = self.transactions.len() - 1 - i;
367 if sid == self.transactions[idx].stream_id {
374 fn find_child_stream_id(&mut self, sid: u32) -> u32 {
375 for i in 0..self.transactions.len() {
376 //reverse order should be faster
377 if sid == self.transactions[self.transactions.len() - 1 - i].stream_id {
378 if self.transactions[self.transactions.len() - 1 - i].child_stream_id > 0 {
379 return self.transactions[self.transactions.len() - 1 - i].child_stream_id;
387 fn create_global_tx(&mut self) -> &mut HTTP2Transaction {
388 //special transaction with only one frame
389 //as it affects the global connection, there is no end to it
390 let mut tx = HTTP2Transaction::new();
392 tx.tx_id = self.tx_id;
393 tx.state = HTTP2TransactionState::HTTP2StateGlobal;
394 self.transactions.push(tx);
395 return self.transactions.last_mut().unwrap();
398 pub fn find_or_create_tx(
399 &mut self, header: &parser::HTTP2FrameHeader, data: &HTTP2FrameTypeData, dir: u8,
400 ) -> &mut HTTP2Transaction {
401 if header.stream_id == 0 {
402 return self.create_global_tx();
404 let sid = match data {
405 //yes, the right stream_id for Suricata is not the header one
406 HTTP2FrameTypeData::PUSHPROMISE(hs) => hs.stream_id,
407 HTTP2FrameTypeData::CONTINUATION(_) => {
408 if dir == STREAM_TOCLIENT {
409 //continuation of a push promise
410 self.find_child_stream_id(header.stream_id)
415 _ => header.stream_id,
417 let index = self.find_tx_index(sid);
419 if self.transactions[index - 1].state == HTTP2TransactionState::HTTP2StateClosed {
420 //these frames can be received in this state for a short period
421 if header.ftype != parser::HTTP2FrameType::RSTSTREAM as u8
422 && header.ftype != parser::HTTP2FrameType::WINDOWUPDATE as u8
423 && header.ftype != parser::HTTP2FrameType::PRIORITY as u8
425 self.set_event(HTTP2Event::StreamIdReuse);
428 return &mut self.transactions[index - 1];
430 let mut tx = HTTP2Transaction::new();
432 tx.tx_id = self.tx_id;
434 tx.state = HTTP2TransactionState::HTTP2StateOpen;
435 self.transactions.push(tx);
436 return self.transactions.last_mut().unwrap();
440 fn process_headers(&mut self, blocks: &Vec<parser::HTTP2FrameHeaderBlock>, dir: u8) {
441 let (mut update, mut sizeup) = (false, 0);
442 for i in 0..blocks.len() {
443 if blocks[i].error >= parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeError {
444 self.set_event(HTTP2Event::InvalidHeader);
445 } else if blocks[i].error
446 == parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate
449 if blocks[i].sizeupdate > sizeup {
450 sizeup = blocks[i].sizeupdate;
455 //borrow checker forbids to pass directly dyn_headers
456 let dyn_headers = if dir == STREAM_TOCLIENT {
457 &mut self.dynamic_headers_tc
459 &mut self.dynamic_headers_ts
461 dyn_headers.max_size = sizeup as usize;
466 &mut self, ftype: u8, input: &[u8], complete: bool, hflags: u8, dir: u8,
467 ) -> HTTP2FrameTypeData {
468 match num::FromPrimitive::from_u8(ftype) {
469 Some(parser::HTTP2FrameType::GOAWAY) => {
470 if input.len() < HTTP2_FRAME_GOAWAY_LEN {
471 self.set_event(HTTP2Event::InvalidFrameLength);
472 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
473 reason: HTTP2FrameUnhandledReason::Incomplete,
476 match parser::http2_parse_frame_goaway(input) {
478 return HTTP2FrameTypeData::GOAWAY(goaway);
481 self.set_event(HTTP2Event::InvalidFrameData);
482 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
483 reason: HTTP2FrameUnhandledReason::ParsingError,
488 Some(parser::HTTP2FrameType::SETTINGS) => {
489 match parser::http2_parse_frame_settings(input) {
491 for i in 0..set.len() {
492 if set[i].id == parser::HTTP2SettingsId::SETTINGSHEADERTABLESIZE {
493 //reverse order as this is what we accept from the other endpoint
494 let dyn_headers = if dir == STREAM_TOCLIENT {
495 &mut self.dynamic_headers_ts
497 &mut self.dynamic_headers_tc
499 dyn_headers.max_size = set[i].value as usize;
500 if set[i].value > HTTP2_MAX_TABLESIZE {
501 //mark potential overflow
502 dyn_headers.overflow = 1;
504 //reset in case peer set a lower value, to be tested
505 dyn_headers.overflow = 0;
509 //we could set an event on remaining data
510 return HTTP2FrameTypeData::SETTINGS(set);
512 Err(nom::Err::Incomplete(_)) => {
514 self.set_event(HTTP2Event::InvalidFrameData);
515 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
516 reason: HTTP2FrameUnhandledReason::ParsingError,
519 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
520 reason: HTTP2FrameUnhandledReason::TooLong,
525 self.set_event(HTTP2Event::InvalidFrameData);
526 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
527 reason: HTTP2FrameUnhandledReason::ParsingError,
532 Some(parser::HTTP2FrameType::RSTSTREAM) => {
533 if input.len() != HTTP2_FRAME_RSTSTREAM_LEN {
534 self.set_event(HTTP2Event::InvalidFrameLength);
535 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
536 reason: HTTP2FrameUnhandledReason::Incomplete,
539 match parser::http2_parse_frame_rststream(input) {
541 return HTTP2FrameTypeData::RSTSTREAM(rst);
544 self.set_event(HTTP2Event::InvalidFrameData);
545 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
546 reason: HTTP2FrameUnhandledReason::ParsingError,
552 Some(parser::HTTP2FrameType::PRIORITY) => {
553 if input.len() != HTTP2_FRAME_PRIORITY_LEN {
554 self.set_event(HTTP2Event::InvalidFrameLength);
555 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
556 reason: HTTP2FrameUnhandledReason::Incomplete,
559 match parser::http2_parse_frame_priority(input) {
560 Ok((_, priority)) => {
561 return HTTP2FrameTypeData::PRIORITY(priority);
564 self.set_event(HTTP2Event::InvalidFrameData);
565 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
566 reason: HTTP2FrameUnhandledReason::ParsingError,
572 Some(parser::HTTP2FrameType::WINDOWUPDATE) => {
573 if input.len() != HTTP2_FRAME_WINDOWUPDATE_LEN {
574 self.set_event(HTTP2Event::InvalidFrameLength);
575 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
576 reason: HTTP2FrameUnhandledReason::Incomplete,
579 match parser::http2_parse_frame_windowupdate(input) {
581 return HTTP2FrameTypeData::WINDOWUPDATE(wu);
584 self.set_event(HTTP2Event::InvalidFrameData);
585 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
586 reason: HTTP2FrameUnhandledReason::ParsingError,
592 Some(parser::HTTP2FrameType::PUSHPROMISE) => {
593 let dyn_headers = if dir == STREAM_TOCLIENT {
594 &mut self.dynamic_headers_tc
596 &mut self.dynamic_headers_ts
598 match parser::http2_parse_frame_push_promise(input, hflags, dyn_headers) {
600 self.process_headers(&hs.blocks, dir);
601 return HTTP2FrameTypeData::PUSHPROMISE(hs);
603 Err(nom::Err::Incomplete(_)) => {
605 self.set_event(HTTP2Event::InvalidFrameData);
606 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
607 reason: HTTP2FrameUnhandledReason::ParsingError,
610 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
611 reason: HTTP2FrameUnhandledReason::TooLong,
616 self.set_event(HTTP2Event::InvalidFrameData);
617 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
618 reason: HTTP2FrameUnhandledReason::ParsingError,
623 Some(parser::HTTP2FrameType::DATA) => {
624 return HTTP2FrameTypeData::DATA;
626 Some(parser::HTTP2FrameType::CONTINUATION) => {
627 let dyn_headers = if dir == STREAM_TOCLIENT {
628 &mut self.dynamic_headers_tc
630 &mut self.dynamic_headers_ts
632 match parser::http2_parse_frame_continuation(input, dyn_headers) {
634 self.process_headers(&hs.blocks, dir);
635 return HTTP2FrameTypeData::CONTINUATION(hs);
637 Err(nom::Err::Incomplete(_)) => {
639 self.set_event(HTTP2Event::InvalidFrameData);
640 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
641 reason: HTTP2FrameUnhandledReason::ParsingError,
644 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
645 reason: HTTP2FrameUnhandledReason::TooLong,
650 self.set_event(HTTP2Event::InvalidFrameData);
651 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
652 reason: HTTP2FrameUnhandledReason::ParsingError,
657 Some(parser::HTTP2FrameType::HEADERS) => {
658 let dyn_headers = if dir == STREAM_TOCLIENT {
659 &mut self.dynamic_headers_tc
661 &mut self.dynamic_headers_ts
663 match parser::http2_parse_frame_headers(input, hflags, dyn_headers) {
665 self.process_headers(&hs.blocks, dir);
667 SCLogDebug!("Remaining data for HTTP2 headers");
668 self.set_event(HTTP2Event::ExtraHeaderData);
670 return HTTP2FrameTypeData::HEADERS(hs);
672 Err(nom::Err::Incomplete(_)) => {
674 self.set_event(HTTP2Event::InvalidFrameData);
675 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
676 reason: HTTP2FrameUnhandledReason::ParsingError,
679 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
680 reason: HTTP2FrameUnhandledReason::TooLong,
685 self.set_event(HTTP2Event::InvalidFrameData);
686 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
687 reason: HTTP2FrameUnhandledReason::ParsingError,
692 Some(parser::HTTP2FrameType::PING) => {
693 return HTTP2FrameTypeData::PING;
696 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
697 reason: HTTP2FrameUnhandledReason::UnknownType,
703 fn parse_frames(&mut self, mut input: &[u8], il: usize, dir: u8) -> AppLayerResult {
704 while input.len() > 0 {
705 match parser::http2_parse_frame_header(input) {
707 let hl = head.length as usize;
709 //we check for completeness first
711 //but limit ourselves so as not to exhaust memory
712 if hl < HTTP2_MAX_HANDLED_FRAME_SIZE {
713 return AppLayerResult::incomplete(
714 (il - input.len()) as u32,
715 (HTTP2_FRAME_HEADER_LEN + hl) as u32,
717 } else if rem.len() < HTTP2_MIN_HANDLED_FRAME_SIZE {
718 return AppLayerResult::incomplete(
719 (il - input.len()) as u32,
720 (HTTP2_FRAME_HEADER_LEN + HTTP2_MIN_HANDLED_FRAME_SIZE) as u32,
723 self.set_event(HTTP2Event::LongFrameData);
724 self.request_frame_size = head.length - (rem.len() as u32);
728 //get a safe length for the buffer
729 let (hlsafe, complete) = if rem.len() < hl {
735 if head.length == 0 && head.ftype == parser::HTTP2FrameType::SETTINGS as u8 {
736 input = &rem[hlsafe..];
739 let txdata = self.parse_frame_data(
747 let tx = self.find_or_create_tx(&head, &txdata, dir);
748 tx.handle_frame(&head, &txdata, dir);
749 let over = head.flags & parser::HTTP2_FLAG_HEADER_EOS != 0;
750 let ftype = head.ftype;
751 let sid = head.stream_id;
752 if dir == STREAM_TOSERVER {
753 tx.frames_ts.push(HTTP2Frame {
758 tx.frames_tc.push(HTTP2Frame {
763 if ftype == parser::HTTP2FrameType::DATA as u8 {
764 match unsafe { SURICATA_HTTP2_FILE_CONFIG } {
766 //borrow checker forbids to reuse directly tx
767 let index = self.find_tx_index(sid);
769 let mut tx_same = &mut self.transactions[index - 1];
770 let xid: u32 = tx_same.tx_id as u32;
771 tx_same.ft.tx_id = tx_same.tx_id - 1;
772 let (files, flags) = self.files.get(dir);
773 tx_same.ft.new_chunk(
779 tx_same.ft.tracked, //offset = append
787 None => panic!("no SURICATA_HTTP2_FILE_CONFIG"),
790 input = &rem[hlsafe..];
792 Err(nom::Err::Incomplete(_)) => {
793 //we may have consumed data from previous records
794 return AppLayerResult::incomplete(
795 (il - input.len()) as u32,
796 HTTP2_FRAME_HEADER_LEN as u32,
800 self.set_event(HTTP2Event::InvalidFrameHeader);
801 return AppLayerResult::err();
805 return AppLayerResult::ok();
808 fn parse_ts(&mut self, mut input: &[u8]) -> AppLayerResult {
809 //very first : skip magic
810 let mut magic_consumed = 0;
811 if self.progress < HTTP2ConnectionState::Http2StateMagicDone {
813 if input.len() >= HTTP2_MAGIC_LEN {
815 match std::str::from_utf8(&input[..HTTP2_MAGIC_LEN]) {
816 Ok("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n") => {
817 input = &input[HTTP2_MAGIC_LEN..];
818 magic_consumed = HTTP2_MAGIC_LEN;
821 self.set_event(HTTP2Event::InvalidClientMagic);
824 return AppLayerResult::err();
827 self.progress = HTTP2ConnectionState::Http2StateMagicDone;
830 return AppLayerResult::incomplete(0 as u32, HTTP2_MAGIC_LEN as u32);
833 //first consume frame bytes
834 let il = input.len();
835 if self.request_frame_size > 0 {
836 let ilen = input.len() as u32;
837 if self.request_frame_size >= ilen {
838 self.request_frame_size -= ilen;
839 return AppLayerResult::ok();
841 let start = self.request_frame_size as usize;
842 input = &input[start..];
843 self.request_frame_size = 0;
847 //then parse all we can
848 let r = self.parse_frames(input, il, STREAM_TOSERVER);
850 //adds bytes consumed by banner to incomplete result
851 return AppLayerResult::incomplete(r.consumed + magic_consumed as u32, r.needed);
857 fn parse_tc(&mut self, mut input: &[u8]) -> AppLayerResult {
858 //first consume frame bytes
859 let il = input.len();
860 if self.response_frame_size > 0 {
861 let ilen = input.len() as u32;
862 if self.response_frame_size >= ilen {
863 self.response_frame_size -= ilen;
864 return AppLayerResult::ok();
866 let start = self.response_frame_size as usize;
867 input = &input[start..];
868 self.response_frame_size = 0;
871 //then parse all we can
872 return self.parse_frames(input, il, STREAM_TOCLIENT);
876 &mut self, min_tx_id: u64, state: &mut u64,
877 ) -> Option<(&HTTP2Transaction, u64, bool)> {
878 let mut index = *state as usize;
879 let len = self.transactions.len();
882 let tx = &self.transactions[index];
883 if tx.tx_id < min_tx_id + 1 {
887 *state = index as u64;
888 return Some((tx, tx.tx_id - 1, (len - index) > 1));
897 export_tx_get_detect_state!(rs_http2_tx_get_detect_state, HTTP2Transaction);
898 export_tx_set_detect_state!(rs_http2_tx_set_detect_state, HTTP2Transaction);
900 export_tx_data_get!(rs_http2_get_tx_data, HTTP2Transaction);
902 /// C entry point for a probing parser.
904 pub extern "C" fn rs_http2_probing_parser_tc(
905 _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8,
907 if input != std::ptr::null_mut() {
908 let slice = build_slice!(input, input_len as usize);
909 match parser::http2_parse_frame_header(slice) {
911 if header.reserved != 0
912 || header.length > HTTP2_DEFAULT_MAX_FRAME_SIZE
913 || header.flags & 0xFE != 0
914 || header.ftype != parser::HTTP2FrameType::SETTINGS as u8
916 return unsafe { ALPROTO_FAILED };
918 return unsafe { ALPROTO_HTTP2 };
920 Err(nom::Err::Incomplete(_)) => {
921 return ALPROTO_UNKNOWN;
924 return unsafe { ALPROTO_FAILED };
928 return ALPROTO_UNKNOWN;
931 /// Extern functions operating on HTTP2.
933 pub fn HTTP2MimicHttp1Request(
934 orig_state: *mut std::os::raw::c_void, new_state: *mut std::os::raw::c_void,
939 pub extern "C" fn rs_http2_state_new(
940 orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto,
941 ) -> *mut std::os::raw::c_void {
942 let state = HTTP2State::new();
943 let boxed = Box::new(state);
944 let r = unsafe { transmute(boxed) };
945 if orig_state != std::ptr::null_mut() {
946 //we could check ALPROTO_HTTP == orig_proto
948 HTTP2MimicHttp1Request(orig_state, r);
955 pub extern "C" fn rs_http2_state_free(state: *mut std::os::raw::c_void) {
957 let mut state: Box<HTTP2State> = unsafe { transmute(state) };
962 pub extern "C" fn rs_http2_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) {
963 let state = cast_pointer!(state, HTTP2State);
964 state.free_tx(tx_id);
968 pub extern "C" fn rs_http2_parse_ts(
969 flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void,
970 input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8,
971 ) -> AppLayerResult {
972 let state = cast_pointer!(state, HTTP2State);
973 let buf = build_slice!(input, input_len as usize);
975 state.files.flags_ts = unsafe { FileFlowToFlags(flow, STREAM_TOSERVER) };
976 state.files.flags_ts = state.files.flags_ts | FILE_USE_DETECT;
977 return state.parse_ts(buf);
981 pub extern "C" fn rs_http2_parse_tc(
982 flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void,
983 input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8,
984 ) -> AppLayerResult {
985 let state = cast_pointer!(state, HTTP2State);
986 let buf = build_slice!(input, input_len as usize);
987 state.files.flags_tc = unsafe { FileFlowToFlags(flow, STREAM_TOCLIENT) };
988 state.files.flags_tc = state.files.flags_tc | FILE_USE_DETECT;
989 return state.parse_tc(buf);
993 pub extern "C" fn rs_http2_state_get_tx(
994 state: *mut std::os::raw::c_void, tx_id: u64,
995 ) -> *mut std::os::raw::c_void {
996 let state = cast_pointer!(state, HTTP2State);
997 match state.get_tx(tx_id) {
999 return unsafe { transmute(tx) };
1002 return std::ptr::null_mut();
1008 pub extern "C" fn rs_http2_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 {
1009 let state = cast_pointer!(state, HTTP2State);
1014 pub extern "C" fn rs_http2_tx_get_state(tx: *mut std::os::raw::c_void) -> HTTP2TransactionState {
1015 let tx = cast_pointer!(tx, HTTP2Transaction);
1020 pub extern "C" fn rs_http2_tx_get_alstate_progress(
1021 tx: *mut std::os::raw::c_void, _direction: u8,
1022 ) -> std::os::raw::c_int {
1023 return rs_http2_tx_get_state(tx) as i32;
1027 pub extern "C" fn rs_http2_state_get_events(
1028 tx: *mut std::os::raw::c_void,
1029 ) -> *mut core::AppLayerDecoderEvents {
1030 let tx = cast_pointer!(tx, HTTP2Transaction);
1035 pub extern "C" fn rs_http2_state_get_event_info(
1036 event_name: *const std::os::raw::c_char, event_id: *mut std::os::raw::c_int,
1037 event_type: *mut core::AppLayerEventType,
1038 ) -> std::os::raw::c_int {
1039 if event_name == std::ptr::null() {
1042 let c_event_name: &CStr = unsafe { CStr::from_ptr(event_name) };
1043 let event = match c_event_name.to_str() {
1046 "invalid_frame_header" => HTTP2Event::InvalidFrameHeader as i32,
1047 "invalid_client_magic" => HTTP2Event::InvalidClientMagic as i32,
1048 "invalid_frame_data" => HTTP2Event::InvalidFrameData as i32,
1049 "invalid_header" => HTTP2Event::InvalidHeader as i32,
1050 "invalid_frame_length" => HTTP2Event::InvalidFrameLength as i32,
1051 "extra_header_data" => HTTP2Event::ExtraHeaderData as i32,
1052 "long_frame_data" => HTTP2Event::LongFrameData as i32,
1053 "stream_id_reuse" => HTTP2Event::StreamIdReuse as i32,
1054 "invalid_http1_settings" => HTTP2Event::InvalidHTTP1Settings as i32,
1055 _ => -1, // unknown event
1058 Err(_) => -1, // UTF-8 conversion failed
1061 *event_type = core::APP_LAYER_EVENT_TYPE_TRANSACTION;
1062 *event_id = event as std::os::raw::c_int;
1068 pub extern "C" fn rs_http2_state_get_event_info_by_id(
1069 event_id: std::os::raw::c_int, event_name: *mut *const std::os::raw::c_char,
1070 event_type: *mut core::AppLayerEventType,
1072 if let Some(e) = HTTP2Event::from_i32(event_id as i32) {
1073 let estr = match e {
1074 HTTP2Event::InvalidFrameHeader => "invalid_frame_header\0",
1075 HTTP2Event::InvalidClientMagic => "invalid_client_magic\0",
1076 HTTP2Event::InvalidFrameData => "invalid_frame_data\0",
1077 HTTP2Event::InvalidHeader => "invalid_header\0",
1078 HTTP2Event::InvalidFrameLength => "invalid_frame_length\0",
1079 HTTP2Event::ExtraHeaderData => "extra_header_data\0",
1080 HTTP2Event::LongFrameData => "long_frame_data\0",
1081 HTTP2Event::StreamIdReuse => "stream_id_reuse\0",
1082 HTTP2Event::InvalidHTTP1Settings => "invalid_http1_settings\0",
1085 *event_name = estr.as_ptr() as *const std::os::raw::c_char;
1086 *event_type = core::APP_LAYER_EVENT_TYPE_TRANSACTION;
1094 pub extern "C" fn rs_http2_state_get_tx_iterator(
1095 _ipproto: u8, _alproto: AppProto, state: *mut std::os::raw::c_void, min_tx_id: u64,
1096 _max_tx_id: u64, istate: &mut u64,
1097 ) -> applayer::AppLayerGetTxIterTuple {
1098 let state = cast_pointer!(state, HTTP2State);
1099 match state.tx_iterator(min_tx_id, istate) {
1100 Some((tx, out_tx_id, has_next)) => {
1101 let c_tx = unsafe { transmute(tx) };
1102 let ires = applayer::AppLayerGetTxIterTuple::with_values(c_tx, out_tx_id, has_next);
1106 return applayer::AppLayerGetTxIterTuple::not_found();
1112 pub extern "C" fn rs_http2_getfiles(
1113 state: *mut std::os::raw::c_void, direction: u8,
1114 ) -> *mut FileContainer {
1115 let state = cast_pointer!(state, HTTP2State);
1116 if direction == STREAM_TOCLIENT {
1117 &mut state.files.files_tc as *mut FileContainer
1119 &mut state.files.files_ts as *mut FileContainer
1123 // Parser name as a C style string.
1124 const PARSER_NAME: &'static [u8] = b"http2\0";
1127 pub unsafe extern "C" fn rs_http2_register_parser() {
1128 let default_port = CString::new("[80]").unwrap();
1129 let parser = RustParser {
1130 name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
1131 default_port: default_port.as_ptr(),
1132 ipproto: IPPROTO_TCP,
1133 probe_ts: None, // big magic string should be enough
1134 probe_tc: Some(rs_http2_probing_parser_tc),
1135 min_depth: HTTP2_FRAME_HEADER_LEN as u16,
1136 max_depth: HTTP2_MAGIC_LEN as u16,
1137 state_new: rs_http2_state_new,
1138 state_free: rs_http2_state_free,
1139 tx_free: rs_http2_state_tx_free,
1140 parse_ts: rs_http2_parse_ts,
1141 parse_tc: rs_http2_parse_tc,
1142 get_tx_count: rs_http2_state_get_tx_count,
1143 get_tx: rs_http2_state_get_tx,
1144 tx_comp_st_ts: HTTP2TransactionState::HTTP2StateClosed as i32,
1145 tx_comp_st_tc: HTTP2TransactionState::HTTP2StateClosed as i32,
1146 tx_get_progress: rs_http2_tx_get_alstate_progress,
1147 get_de_state: rs_http2_tx_get_detect_state,
1148 set_de_state: rs_http2_tx_set_detect_state,
1149 get_events: Some(rs_http2_state_get_events),
1150 get_eventinfo: Some(rs_http2_state_get_event_info),
1151 get_eventinfo_byid: Some(rs_http2_state_get_event_info_by_id),
1152 localstorage_new: None,
1153 localstorage_free: None,
1154 get_files: Some(rs_http2_getfiles),
1155 get_tx_iterator: Some(rs_http2_state_get_tx_iterator),
1156 get_tx_data: rs_http2_get_tx_data,
1157 apply_tx_config: None,
1162 let ip_proto_str = CString::new("tcp").unwrap();
1164 if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
1165 let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
1166 ALPROTO_HTTP2 = alproto;
1167 if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
1168 let _ = AppLayerRegisterParser(&parser, alproto);
1170 SCLogDebug!("Rust http2 parser registered.");
1172 SCLogNotice!("Protocol detector and parser disabled for HTTP2.");