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