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