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
20 use crate::applayer::{self, *};
22 self, AppProto, Flow, SuricataFileContext, ALPROTO_FAILED, ALPROTO_UNKNOWN, IPPROTO_TCP,
23 STREAM_TOCLIENT, STREAM_TOSERVER,
25 use crate::filecontainer::*;
26 use crate::filetracker::*;
29 use std::ffi::{CStr, CString};
31 use std::mem::transmute;
33 static mut ALPROTO_HTTP2: AppProto = ALPROTO_UNKNOWN;
35 const HTTP2_DEFAULT_MAX_FRAME_SIZE: u32 = 16384;
36 const HTTP2_MAX_HANDLED_FRAME_SIZE: usize = 65536;
37 const HTTP2_MIN_HANDLED_FRAME_SIZE: usize = 256;
39 pub static mut SURICATA_HTTP2_FILE_CONFIG: Option<&'static SuricataFileContext> = None;
42 pub extern "C" fn rs_http2_init(context: &'static mut SuricataFileContext) {
44 SURICATA_HTTP2_FILE_CONFIG = Some(context);
49 #[derive(Copy, Clone, PartialOrd, PartialEq)]
50 pub enum HTTP2ConnectionState {
52 Http2StateMagicDone = 1,
55 const HTTP2_FRAME_HEADER_LEN: usize = 9;
56 const HTTP2_MAGIC_LEN: usize = 24;
57 const HTTP2_FRAME_GOAWAY_LEN: usize = 4;
58 const HTTP2_FRAME_RSTSTREAM_LEN: usize = 4;
59 const HTTP2_FRAME_PRIORITY_LEN: usize = 1;
60 const HTTP2_FRAME_WINDOWUPDATE_LEN: usize = 4;
61 //TODO make this configurable
62 pub const HTTP2_MAX_TABLESIZE: u32 = 0x10000; // 65536
65 #[derive(Copy, Clone, PartialOrd, PartialEq, Debug)]
66 pub enum HTTP2FrameUnhandledReason {
73 impl fmt::Display for HTTP2FrameUnhandledReason {
74 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75 write!(f, "{:?}", self)
80 pub struct HTTP2FrameUnhandled {
81 pub reason: HTTP2FrameUnhandledReason,
84 pub enum HTTP2FrameTypeData {
85 PRIORITY(parser::HTTP2FramePriority),
86 GOAWAY(parser::HTTP2FrameGoAway),
87 RSTSTREAM(parser::HTTP2FrameRstStream),
88 SETTINGS(Vec<parser::HTTP2FrameSettings>),
89 WINDOWUPDATE(parser::HTTP2FrameWindowUpdate),
90 HEADERS(parser::HTTP2FrameHeaders),
91 PUSHPROMISE(parser::HTTP2FramePushPromise),
92 CONTINUATION(parser::HTTP2FrameContinuation),
96 UNHANDLED(HTTP2FrameUnhandled),
100 #[derive(Copy, Clone, PartialOrd, PartialEq, Debug)]
101 pub enum HTTP2TransactionState {
104 HTTP2StateReserved = 2,
105 HTTP2StateDataClient = 3,
106 HTTP2StateHalfClosedClient = 4,
107 HTTP2StateDataServer = 5,
108 HTTP2StateHalfClosedServer = 6,
109 HTTP2StateClosed = 7,
110 //not a RFC-defined state, used for stream 0 frames appyling to the global connection
111 HTTP2StateGlobal = 8,
114 pub struct HTTP2Frame {
115 pub header: parser::HTTP2FrameHeader,
116 pub data: HTTP2FrameTypeData,
119 pub struct HTTP2Transaction {
122 pub state: HTTP2TransactionState,
123 child_stream_id: u32,
125 pub frames_tc: Vec<HTTP2Frame>,
126 pub frames_ts: Vec<HTTP2Frame>,
128 de_state: Option<*mut core::DetectEngineState>,
129 events: *mut core::AppLayerDecoderEvents,
130 tx_data: AppLayerTxData,
131 ft: FileTransferTracker,
133 //temporary escaped header for detection
134 //must be attached to transaction for memory management (be freed at the right time)
135 pub escaped: Vec<Vec<u8>>,
138 impl HTTP2Transaction {
139 pub fn new() -> HTTP2Transaction {
144 state: HTTP2TransactionState::HTTP2StateIdle,
145 frames_tc: Vec::new(),
146 frames_ts: Vec::new(),
148 events: std::ptr::null_mut(),
149 tx_data: AppLayerTxData::new(),
150 ft: FileTransferTracker::new(),
151 escaped: Vec::with_capacity(16),
155 pub fn free(&mut self) {
156 if self.events != std::ptr::null_mut() {
157 core::sc_app_layer_decoder_events_free_events(&mut self.events);
159 if let Some(state) = self.de_state {
160 core::sc_detect_engine_state_free(state);
165 &mut self, header: &parser::HTTP2FrameHeader, data: &HTTP2FrameTypeData, dir: u8,
167 //handle child_stream_id changes
169 HTTP2FrameTypeData::PUSHPROMISE(hs) => {
170 if dir == STREAM_TOCLIENT {
171 //we could set an event if self.child_stream_id != 0
172 if header.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS == 0 {
173 self.child_stream_id = hs.stream_id;
175 self.state = HTTP2TransactionState::HTTP2StateReserved;
178 HTTP2FrameTypeData::CONTINUATION(_) => {
179 if dir == STREAM_TOCLIENT
180 && header.flags & parser::HTTP2_FLAG_HEADER_END_HEADERS != 0
182 self.child_stream_id = 0;
185 HTTP2FrameTypeData::HEADERS(_) => {
186 if dir == STREAM_TOCLIENT {
187 self.child_stream_id = 0;
190 HTTP2FrameTypeData::RSTSTREAM(_) => {
191 self.child_stream_id = 0;
195 //handle closing state changes
197 HTTP2FrameTypeData::HEADERS(_) | HTTP2FrameTypeData::DATA => {
198 if header.flags & parser::HTTP2_FLAG_HEADER_EOS != 0 {
200 HTTP2TransactionState::HTTP2StateHalfClosedClient
201 | HTTP2TransactionState::HTTP2StateDataServer => {
202 if dir == STREAM_TOCLIENT {
203 self.state = HTTP2TransactionState::HTTP2StateClosed;
206 HTTP2TransactionState::HTTP2StateHalfClosedServer => {
207 if dir == STREAM_TOSERVER {
208 self.state = HTTP2TransactionState::HTTP2StateClosed;
211 // do not revert back to a half closed state
212 HTTP2TransactionState::HTTP2StateClosed => {}
213 HTTP2TransactionState::HTTP2StateGlobal => {}
215 if dir == STREAM_TOCLIENT {
216 self.state = HTTP2TransactionState::HTTP2StateHalfClosedServer;
218 self.state = HTTP2TransactionState::HTTP2StateHalfClosedClient;
222 } else if header.ftype == parser::HTTP2FrameType::DATA as u8 {
224 if dir == STREAM_TOSERVER {
225 if self.state < HTTP2TransactionState::HTTP2StateDataClient {
226 self.state = HTTP2TransactionState::HTTP2StateDataClient;
229 if self.state < HTTP2TransactionState::HTTP2StateDataServer {
230 self.state = HTTP2TransactionState::HTTP2StateDataServer;
240 impl Drop for HTTP2Transaction {
247 pub enum HTTP2Event {
248 InvalidFrameHeader = 0,
256 InvalidHTTP1Settings,
260 fn from_i32(value: i32) -> Option<HTTP2Event> {
262 0 => Some(HTTP2Event::InvalidFrameHeader),
263 1 => Some(HTTP2Event::InvalidClientMagic),
264 2 => Some(HTTP2Event::InvalidFrameData),
265 3 => Some(HTTP2Event::InvalidHeader),
266 4 => Some(HTTP2Event::InvalidFrameLength),
267 5 => Some(HTTP2Event::ExtraHeaderData),
268 6 => Some(HTTP2Event::LongFrameData),
269 7 => Some(HTTP2Event::StreamIdReuse),
270 8 => Some(HTTP2Event::InvalidHTTP1Settings),
276 pub struct HTTP2DynTable {
277 pub table: Vec<parser::HTTP2FrameHeaderBlock>,
278 pub current_size: usize,
284 pub fn new() -> Self {
286 table: Vec::with_capacity(64),
288 max_size: 4096, //default value
294 pub struct HTTP2State {
296 request_frame_size: u32,
297 response_frame_size: u32,
298 dynamic_headers_ts: HTTP2DynTable,
299 dynamic_headers_tc: HTTP2DynTable,
300 transactions: Vec<HTTP2Transaction>,
301 progress: HTTP2ConnectionState,
302 pub files: HTTP2Files,
306 pub fn new() -> Self {
309 request_frame_size: 0,
310 response_frame_size: 0,
311 // the headers are encoded on one byte
312 // with a fixed number of static headers, and
313 // a variable number of dynamic headers
314 dynamic_headers_ts: HTTP2DynTable::new(),
315 dynamic_headers_tc: HTTP2DynTable::new(),
316 transactions: Vec::new(),
317 progress: HTTP2ConnectionState::Http2StateInit,
318 files: HTTP2Files::new(),
322 pub fn free(&mut self) {
323 self.transactions.clear();
327 pub fn set_event(&mut self, event: HTTP2Event) {
328 let len = self.transactions.len();
332 let tx = &mut self.transactions[len - 1];
333 let ev = event as u8;
334 core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events, ev);
337 // Free a transaction by ID.
338 fn free_tx(&mut self, tx_id: u64) {
339 let len = self.transactions.len();
340 let mut found = false;
343 let tx = &self.transactions[i];
344 if tx.tx_id == tx_id + 1 {
351 self.transactions.remove(index);
355 pub fn get_tx(&mut self, tx_id: u64) -> Option<&HTTP2Transaction> {
356 for tx in &mut self.transactions {
357 if tx.tx_id == tx_id + 1 {
364 fn find_tx_index(&mut self, sid: u32, header: &parser::HTTP2FrameHeader) -> usize {
365 for i in 0..self.transactions.len() {
366 //reverse order should be faster
367 let idx = self.transactions.len() - 1 - i;
368 if sid == self.transactions[idx].stream_id {
369 if self.transactions[idx].state == HTTP2TransactionState::HTTP2StateClosed {
370 //these frames can be received in this state for a short period
371 if header.ftype != parser::HTTP2FrameType::RSTSTREAM as u8
372 && header.ftype != parser::HTTP2FrameType::WINDOWUPDATE as u8
373 && header.ftype != parser::HTTP2FrameType::PRIORITY as u8
375 self.set_event(HTTP2Event::StreamIdReuse);
384 fn find_child_stream_id(&mut self, sid: u32) -> u32 {
385 for i in 0..self.transactions.len() {
386 //reverse order should be faster
387 if sid == self.transactions[self.transactions.len() - 1 - i].stream_id {
388 if self.transactions[self.transactions.len() - 1 - i].child_stream_id > 0 {
389 return self.transactions[self.transactions.len() - 1 - i].child_stream_id;
397 fn create_global_tx(&mut self) -> &mut HTTP2Transaction {
398 //special transaction with only one frame
399 //as it affects the global connection, there is no end to it
400 let mut tx = HTTP2Transaction::new();
402 tx.tx_id = self.tx_id;
403 tx.state = HTTP2TransactionState::HTTP2StateGlobal;
404 self.transactions.push(tx);
405 return self.transactions.last_mut().unwrap();
408 pub fn find_or_create_tx(
409 &mut self, header: &parser::HTTP2FrameHeader, data: &HTTP2FrameTypeData, dir: u8,
410 ) -> &mut HTTP2Transaction {
411 if header.stream_id == 0 {
412 return self.create_global_tx();
414 let sid = match data {
415 //yes, the right stream_id for Suricata is not the header one
416 HTTP2FrameTypeData::PUSHPROMISE(hs) => hs.stream_id,
417 HTTP2FrameTypeData::CONTINUATION(_) => {
418 if dir == STREAM_TOCLIENT {
419 //continuation of a push promise
420 self.find_child_stream_id(header.stream_id)
425 _ => header.stream_id,
427 let index = self.find_tx_index(sid, header);
429 return &mut self.transactions[index - 1];
431 let mut tx = HTTP2Transaction::new();
433 tx.tx_id = self.tx_id;
435 tx.state = HTTP2TransactionState::HTTP2StateOpen;
436 self.transactions.push(tx);
437 return self.transactions.last_mut().unwrap();
442 &mut self, ftype: u8, input: &[u8], complete: bool, hflags: u8, dir: u8,
443 ) -> HTTP2FrameTypeData {
444 match num::FromPrimitive::from_u8(ftype) {
445 Some(parser::HTTP2FrameType::GOAWAY) => {
446 if input.len() < HTTP2_FRAME_GOAWAY_LEN {
447 self.set_event(HTTP2Event::InvalidFrameLength);
448 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
449 reason: HTTP2FrameUnhandledReason::Incomplete,
452 match parser::http2_parse_frame_goaway(input) {
454 return HTTP2FrameTypeData::GOAWAY(goaway);
457 self.set_event(HTTP2Event::InvalidFrameData);
458 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
459 reason: HTTP2FrameUnhandledReason::ParsingError,
464 Some(parser::HTTP2FrameType::SETTINGS) => {
465 match parser::http2_parse_frame_settings(input) {
467 for i in 0..set.len() {
468 if set[i].id == parser::HTTP2SettingsId::SETTINGSHEADERTABLESIZE {
469 //set for both endpoints ? to be tested
470 self.dynamic_headers_tc.max_size = set[i].value as usize;
471 self.dynamic_headers_ts.max_size = set[i].value as usize;
472 if set[i].value > HTTP2_MAX_TABLESIZE {
473 //mark potential overflow
474 self.dynamic_headers_tc.overflow = 1;
475 self.dynamic_headers_ts.overflow = 1;
477 //reset in case peer set a lower value, to be tested
478 self.dynamic_headers_tc.overflow = 0;
479 self.dynamic_headers_ts.overflow = 0;
483 //we could set an event on remaining data
484 return HTTP2FrameTypeData::SETTINGS(set);
486 Err(nom::Err::Incomplete(_)) => {
488 self.set_event(HTTP2Event::InvalidFrameData);
489 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
490 reason: HTTP2FrameUnhandledReason::ParsingError,
493 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
494 reason: HTTP2FrameUnhandledReason::TooLong,
499 self.set_event(HTTP2Event::InvalidFrameData);
500 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
501 reason: HTTP2FrameUnhandledReason::ParsingError,
506 Some(parser::HTTP2FrameType::RSTSTREAM) => {
507 if input.len() != HTTP2_FRAME_RSTSTREAM_LEN {
508 self.set_event(HTTP2Event::InvalidFrameLength);
509 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
510 reason: HTTP2FrameUnhandledReason::Incomplete,
513 match parser::http2_parse_frame_rststream(input) {
515 return HTTP2FrameTypeData::RSTSTREAM(rst);
518 self.set_event(HTTP2Event::InvalidFrameData);
519 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
520 reason: HTTP2FrameUnhandledReason::ParsingError,
526 Some(parser::HTTP2FrameType::PRIORITY) => {
527 if input.len() != HTTP2_FRAME_PRIORITY_LEN {
528 self.set_event(HTTP2Event::InvalidFrameLength);
529 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
530 reason: HTTP2FrameUnhandledReason::Incomplete,
533 match parser::http2_parse_frame_priority(input) {
534 Ok((_, priority)) => {
535 return HTTP2FrameTypeData::PRIORITY(priority);
538 self.set_event(HTTP2Event::InvalidFrameData);
539 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
540 reason: HTTP2FrameUnhandledReason::ParsingError,
546 Some(parser::HTTP2FrameType::WINDOWUPDATE) => {
547 if input.len() != HTTP2_FRAME_WINDOWUPDATE_LEN {
548 self.set_event(HTTP2Event::InvalidFrameLength);
549 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
550 reason: HTTP2FrameUnhandledReason::Incomplete,
553 match parser::http2_parse_frame_windowupdate(input) {
555 return HTTP2FrameTypeData::WINDOWUPDATE(wu);
558 self.set_event(HTTP2Event::InvalidFrameData);
559 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
560 reason: HTTP2FrameUnhandledReason::ParsingError,
566 Some(parser::HTTP2FrameType::PUSHPROMISE) => {
567 let dyn_headers = if dir == STREAM_TOCLIENT {
568 &mut self.dynamic_headers_tc
570 &mut self.dynamic_headers_ts
572 match parser::http2_parse_frame_push_promise(input, hflags, dyn_headers) {
574 for i in 0..hs.blocks.len() {
575 if hs.blocks[i].error
576 >= parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeError
578 self.set_event(HTTP2Event::InvalidHeader);
581 return HTTP2FrameTypeData::PUSHPROMISE(hs);
583 Err(nom::Err::Incomplete(_)) => {
585 self.set_event(HTTP2Event::InvalidFrameData);
586 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
587 reason: HTTP2FrameUnhandledReason::ParsingError,
590 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
591 reason: HTTP2FrameUnhandledReason::TooLong,
596 self.set_event(HTTP2Event::InvalidFrameData);
597 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
598 reason: HTTP2FrameUnhandledReason::ParsingError,
603 Some(parser::HTTP2FrameType::DATA) => {
604 return HTTP2FrameTypeData::DATA;
606 Some(parser::HTTP2FrameType::CONTINUATION) => {
607 let dyn_headers = if dir == STREAM_TOCLIENT {
608 &mut self.dynamic_headers_tc
610 &mut self.dynamic_headers_ts
612 match parser::http2_parse_frame_continuation(input, dyn_headers) {
614 for i in 0..hs.blocks.len() {
615 if hs.blocks[i].error
616 >= parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeError
618 self.set_event(HTTP2Event::InvalidHeader);
621 return HTTP2FrameTypeData::CONTINUATION(hs);
623 Err(nom::Err::Incomplete(_)) => {
625 self.set_event(HTTP2Event::InvalidFrameData);
626 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
627 reason: HTTP2FrameUnhandledReason::ParsingError,
630 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
631 reason: HTTP2FrameUnhandledReason::TooLong,
636 self.set_event(HTTP2Event::InvalidFrameData);
637 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
638 reason: HTTP2FrameUnhandledReason::ParsingError,
643 Some(parser::HTTP2FrameType::HEADERS) => {
644 let dyn_headers = if dir == STREAM_TOCLIENT {
645 &mut self.dynamic_headers_tc
647 &mut self.dynamic_headers_ts
649 match parser::http2_parse_frame_headers(input, hflags, dyn_headers) {
651 for i in 0..hs.blocks.len() {
652 if hs.blocks[i].error
653 >= parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeError
655 self.set_event(HTTP2Event::InvalidHeader);
659 SCLogDebug!("Remaining data for HTTP2 headers");
660 self.set_event(HTTP2Event::ExtraHeaderData);
662 return HTTP2FrameTypeData::HEADERS(hs);
664 Err(nom::Err::Incomplete(_)) => {
666 self.set_event(HTTP2Event::InvalidFrameData);
667 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
668 reason: HTTP2FrameUnhandledReason::ParsingError,
671 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
672 reason: HTTP2FrameUnhandledReason::TooLong,
677 self.set_event(HTTP2Event::InvalidFrameData);
678 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
679 reason: HTTP2FrameUnhandledReason::ParsingError,
684 Some(parser::HTTP2FrameType::PING) => {
685 return HTTP2FrameTypeData::PING;
688 return HTTP2FrameTypeData::UNHANDLED(HTTP2FrameUnhandled {
689 reason: HTTP2FrameUnhandledReason::UnknownType,
695 fn stream_data(&mut self, dir: u8, input: &[u8], over: bool, txid: u64) {
696 match unsafe { SURICATA_HTTP2_FILE_CONFIG } {
698 for tx in &mut self.transactions {
699 if tx.tx_id == txid {
700 let xid: u32 = tx.tx_id as u32;
701 let (files, flags) = self.files.get(dir);
702 tx.ft.tx_id = tx.tx_id;
709 tx.ft.tracked, //offset = append
719 None => panic!("BUG"),
723 fn parse_frames(&mut self, mut input: &[u8], il: usize, dir: u8) -> AppLayerResult {
724 while input.len() > 0 {
725 match parser::http2_parse_frame_header(input) {
727 let hl = head.length as usize;
729 //we check for completeness first
731 //but limit ourselves so as not to exhaust memory
732 if hl < HTTP2_MAX_HANDLED_FRAME_SIZE {
733 return AppLayerResult::incomplete(
734 (il - input.len()) as u32,
735 (HTTP2_FRAME_HEADER_LEN + hl) as u32,
737 } else if rem.len() < HTTP2_MIN_HANDLED_FRAME_SIZE {
738 return AppLayerResult::incomplete(
739 (il - input.len()) as u32,
740 (HTTP2_FRAME_HEADER_LEN + HTTP2_MIN_HANDLED_FRAME_SIZE) as u32,
743 self.set_event(HTTP2Event::LongFrameData);
744 self.request_frame_size = head.length - (rem.len() as u32);
748 //get a safe length for the buffer
749 let (hlsafe, complete) = if rem.len() < hl {
755 if head.length == 0 && head.ftype == parser::HTTP2FrameType::SETTINGS as u8 {
756 input = &rem[hlsafe..];
759 let txdata = self.parse_frame_data(
767 let tx = self.find_or_create_tx(&head, &txdata, dir);
768 tx.handle_frame(&head, &txdata, dir);
769 let over = head.flags & parser::HTTP2_FLAG_HEADER_EOS != 0;
771 let ftype = head.ftype;
772 if dir == STREAM_TOSERVER {
773 tx.frames_ts.push(HTTP2Frame {
778 tx.frames_tc.push(HTTP2Frame {
783 if ftype == parser::HTTP2FrameType::DATA as u8 {
784 self.stream_data(dir, &rem[..hlsafe], over, txid);
786 input = &rem[hlsafe..];
788 Err(nom::Err::Incomplete(_)) => {
789 //we may have consumed data from previous records
790 return AppLayerResult::incomplete(
791 (il - input.len()) as u32,
792 HTTP2_FRAME_HEADER_LEN as u32,
796 self.set_event(HTTP2Event::InvalidFrameHeader);
797 return AppLayerResult::err();
801 return AppLayerResult::ok();
804 fn parse_ts(&mut self, mut input: &[u8]) -> AppLayerResult {
805 //very first : skip magic
806 let mut magic_consumed = 0;
807 if self.progress < HTTP2ConnectionState::Http2StateMagicDone {
809 if input.len() >= HTTP2_MAGIC_LEN {
811 match std::str::from_utf8(&input[..HTTP2_MAGIC_LEN]) {
812 Ok("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n") => {
813 input = &input[HTTP2_MAGIC_LEN..];
814 magic_consumed = HTTP2_MAGIC_LEN;
817 self.set_event(HTTP2Event::InvalidClientMagic);
820 return AppLayerResult::err();
823 self.progress = HTTP2ConnectionState::Http2StateMagicDone;
826 return AppLayerResult::incomplete(0 as u32, HTTP2_MAGIC_LEN as u32);
829 //first consume frame bytes
830 let il = input.len();
831 if self.request_frame_size > 0 {
832 let ilen = input.len() as u32;
833 if self.request_frame_size >= ilen {
834 self.request_frame_size -= ilen;
835 return AppLayerResult::ok();
837 let start = self.request_frame_size as usize;
838 input = &input[start..];
839 self.request_frame_size = 0;
843 //then parse all we can
844 let r = self.parse_frames(input, il, STREAM_TOSERVER);
846 //adds bytes consumed by banner to incomplete result
847 return AppLayerResult::incomplete(r.consumed + magic_consumed as u32, r.needed);
853 fn parse_tc(&mut self, mut input: &[u8]) -> AppLayerResult {
854 //first consume frame bytes
855 let il = input.len();
856 if self.response_frame_size > 0 {
857 let ilen = input.len() as u32;
858 if self.response_frame_size >= ilen {
859 self.response_frame_size -= ilen;
860 return AppLayerResult::ok();
862 let start = self.response_frame_size as usize;
863 input = &input[start..];
864 self.response_frame_size = 0;
867 //then parse all we can
868 return self.parse_frames(input, il, STREAM_TOCLIENT);
872 &mut self, min_tx_id: u64, state: &mut u64,
873 ) -> Option<(&HTTP2Transaction, u64, bool)> {
874 let mut index = *state as usize;
875 let len = self.transactions.len();
878 let tx = &self.transactions[index];
879 if tx.tx_id < min_tx_id + 1 {
883 *state = index as u64;
884 return Some((tx, tx.tx_id - 1, (len - index) > 1));
893 export_tx_get_detect_state!(rs_http2_tx_get_detect_state, HTTP2Transaction);
894 export_tx_set_detect_state!(rs_http2_tx_set_detect_state, HTTP2Transaction);
896 export_tx_data_get!(rs_http2_get_tx_data, HTTP2Transaction);
898 /// C entry point for a probing parser.
900 pub extern "C" fn rs_http2_probing_parser_tc(
901 _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8,
903 if input != std::ptr::null_mut() {
904 let slice = build_slice!(input, input_len as usize);
905 match parser::http2_parse_frame_header(slice) {
907 if header.reserved != 0
908 || header.length > HTTP2_DEFAULT_MAX_FRAME_SIZE
909 || header.flags & 0xFE != 0
910 || header.ftype != parser::HTTP2FrameType::SETTINGS as u8
912 return unsafe { ALPROTO_FAILED };
914 return unsafe { ALPROTO_HTTP2 };
916 Err(nom::Err::Incomplete(_)) => {
917 return ALPROTO_UNKNOWN;
920 return unsafe { ALPROTO_FAILED };
924 return ALPROTO_UNKNOWN;
927 /// Extern functions operating on HTTP2.
929 pub fn HTTP2MimicHttp1Request(
930 orig_state: *mut std::os::raw::c_void, new_state: *mut std::os::raw::c_void,
935 pub extern "C" fn rs_http2_state_new(
936 orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto,
937 ) -> *mut std::os::raw::c_void {
938 let state = HTTP2State::new();
939 let boxed = Box::new(state);
940 let r = unsafe { transmute(boxed) };
941 if orig_state != std::ptr::null_mut() {
942 //we could check ALPROTO_HTTP == orig_proto
944 HTTP2MimicHttp1Request(orig_state, r);
951 pub extern "C" fn rs_http2_state_free(state: *mut std::os::raw::c_void) {
953 let mut state: Box<HTTP2State> = unsafe { transmute(state) };
958 pub extern "C" fn rs_http2_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) {
959 let state = cast_pointer!(state, HTTP2State);
960 state.free_tx(tx_id);
964 pub extern "C" fn rs_http2_parse_ts(
965 flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void,
966 input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8,
967 ) -> AppLayerResult {
968 let state = cast_pointer!(state, HTTP2State);
969 let buf = build_slice!(input, input_len as usize);
971 state.files.flags_ts = unsafe { FileFlowToFlags(flow, STREAM_TOSERVER) };
972 return state.parse_ts(buf);
976 pub extern "C" fn rs_http2_parse_tc(
977 flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void,
978 input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8,
979 ) -> AppLayerResult {
980 let state = cast_pointer!(state, HTTP2State);
981 let buf = build_slice!(input, input_len as usize);
982 state.files.flags_tc = unsafe { FileFlowToFlags(flow, STREAM_TOCLIENT) };
983 return state.parse_tc(buf);
987 pub extern "C" fn rs_http2_state_get_tx(
988 state: *mut std::os::raw::c_void, tx_id: u64,
989 ) -> *mut std::os::raw::c_void {
990 let state = cast_pointer!(state, HTTP2State);
991 match state.get_tx(tx_id) {
993 return unsafe { transmute(tx) };
996 return std::ptr::null_mut();
1002 pub extern "C" fn rs_http2_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 {
1003 let state = cast_pointer!(state, HTTP2State);
1008 pub extern "C" fn rs_http2_state_progress_completion_status(_direction: u8) -> std::os::raw::c_int {
1009 return HTTP2TransactionState::HTTP2StateClosed as i32;
1013 pub extern "C" fn rs_http2_tx_get_state(tx: *mut std::os::raw::c_void) -> HTTP2TransactionState {
1014 let tx = cast_pointer!(tx, HTTP2Transaction);
1019 pub extern "C" fn rs_http2_tx_get_alstate_progress(
1020 tx: *mut std::os::raw::c_void, _direction: u8,
1021 ) -> std::os::raw::c_int {
1022 return rs_http2_tx_get_state(tx) as i32;
1026 pub extern "C" fn rs_http2_state_get_events(
1027 tx: *mut std::os::raw::c_void,
1028 ) -> *mut core::AppLayerDecoderEvents {
1029 let tx = cast_pointer!(tx, HTTP2Transaction);
1034 pub extern "C" fn rs_http2_state_get_event_info(
1035 event_name: *const std::os::raw::c_char, event_id: *mut std::os::raw::c_int,
1036 event_type: *mut core::AppLayerEventType,
1037 ) -> std::os::raw::c_int {
1038 if event_name == std::ptr::null() {
1041 let c_event_name: &CStr = unsafe { CStr::from_ptr(event_name) };
1042 let event = match c_event_name.to_str() {
1045 "invalid_frame_header" => HTTP2Event::InvalidFrameHeader as i32,
1046 "invalid_client_magic" => HTTP2Event::InvalidClientMagic as i32,
1047 "invalid_frame_data" => HTTP2Event::InvalidFrameData as i32,
1048 "invalid_header" => HTTP2Event::InvalidHeader as i32,
1049 "invalid_frame_length" => HTTP2Event::InvalidFrameLength as i32,
1050 "extra_header_data" => HTTP2Event::ExtraHeaderData as i32,
1051 "long_frame_data" => HTTP2Event::LongFrameData as i32,
1052 "stream_id_reuse" => HTTP2Event::StreamIdReuse as i32,
1053 "invalid_http1_settings" => HTTP2Event::InvalidHTTP1Settings as i32,
1054 _ => -1, // unknown event
1057 Err(_) => -1, // UTF-8 conversion failed
1060 *event_type = core::APP_LAYER_EVENT_TYPE_TRANSACTION;
1061 *event_id = event as std::os::raw::c_int;
1067 pub extern "C" fn rs_http2_state_get_event_info_by_id(
1068 event_id: std::os::raw::c_int, event_name: *mut *const std::os::raw::c_char,
1069 event_type: *mut core::AppLayerEventType,
1071 if let Some(e) = HTTP2Event::from_i32(event_id as i32) {
1072 let estr = match e {
1073 HTTP2Event::InvalidFrameHeader => "invalid_frame_header\0",
1074 HTTP2Event::InvalidClientMagic => "invalid_client_magic\0",
1075 HTTP2Event::InvalidFrameData => "invalid_frame_data\0",
1076 HTTP2Event::InvalidHeader => "invalid_header\0",
1077 HTTP2Event::InvalidFrameLength => "invalid_frame_length\0",
1078 HTTP2Event::ExtraHeaderData => "extra_header_data\0",
1079 HTTP2Event::LongFrameData => "long_frame_data\0",
1080 HTTP2Event::StreamIdReuse => "stream_id_reuse\0",
1081 HTTP2Event::InvalidHTTP1Settings => "invalid_http1_settings\0",
1084 *event_name = estr.as_ptr() as *const std::os::raw::c_char;
1085 *event_type = core::APP_LAYER_EVENT_TYPE_TRANSACTION;
1093 pub extern "C" fn rs_http2_state_get_tx_iterator(
1094 _ipproto: u8, _alproto: AppProto, state: *mut std::os::raw::c_void, min_tx_id: u64,
1095 _max_tx_id: u64, istate: &mut u64,
1096 ) -> applayer::AppLayerGetTxIterTuple {
1097 let state = cast_pointer!(state, HTTP2State);
1098 match state.tx_iterator(min_tx_id, istate) {
1099 Some((tx, out_tx_id, has_next)) => {
1100 let c_tx = unsafe { transmute(tx) };
1101 let ires = applayer::AppLayerGetTxIterTuple::with_values(c_tx, out_tx_id, has_next);
1105 return applayer::AppLayerGetTxIterTuple::not_found();
1111 pub extern "C" fn rs_http2_getfiles(
1112 state: *mut std::os::raw::c_void, direction: u8,
1113 ) -> *mut FileContainer {
1114 let state = cast_pointer!(state, HTTP2State);
1115 if direction == STREAM_TOCLIENT {
1116 &mut state.files.files_tc as *mut FileContainer
1118 &mut state.files.files_ts as *mut FileContainer
1122 // Parser name as a C style string.
1123 const PARSER_NAME: &'static [u8] = b"http2\0";
1126 pub unsafe extern "C" fn rs_http2_register_parser() {
1127 let default_port = CString::new("[80]").unwrap();
1128 let parser = RustParser {
1129 name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
1130 default_port: default_port.as_ptr(),
1131 ipproto: IPPROTO_TCP,
1132 probe_ts: None, // big magic string should be enough
1133 probe_tc: Some(rs_http2_probing_parser_tc),
1134 min_depth: HTTP2_FRAME_HEADER_LEN as u16,
1135 max_depth: HTTP2_MAGIC_LEN as u16,
1136 state_new: rs_http2_state_new,
1137 state_free: rs_http2_state_free,
1138 tx_free: rs_http2_state_tx_free,
1139 parse_ts: rs_http2_parse_ts,
1140 parse_tc: rs_http2_parse_tc,
1141 get_tx_count: rs_http2_state_get_tx_count,
1142 get_tx: rs_http2_state_get_tx,
1143 tx_get_comp_st: rs_http2_state_progress_completion_status,
1144 tx_get_progress: rs_http2_tx_get_alstate_progress,
1145 get_de_state: rs_http2_tx_get_detect_state,
1146 set_de_state: rs_http2_tx_set_detect_state,
1147 get_events: Some(rs_http2_state_get_events),
1148 get_eventinfo: Some(rs_http2_state_get_event_info),
1149 get_eventinfo_byid: Some(rs_http2_state_get_event_info_by_id),
1150 localstorage_new: None,
1151 localstorage_free: None,
1152 get_files: Some(rs_http2_getfiles),
1153 get_tx_iterator: Some(rs_http2_state_get_tx_iterator),
1154 get_tx_data: rs_http2_get_tx_data,
1155 apply_tx_config: None,
1160 let ip_proto_str = CString::new("tcp").unwrap();
1162 if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
1163 let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
1164 ALPROTO_HTTP2 = alproto;
1165 if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
1166 let _ = AppLayerRegisterParser(&parser, alproto);
1168 SCLogDebug!("Rust http2 parser registered.");
1170 SCLogNotice!("Protocol detector and parser disabled for HTTP2.");