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