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