http2: settings from http1 upgrade

pull/5403/head
Philippe Antoine 5 years ago committed by Victor Julien
parent 7011bddf84
commit 6694737fcf

@ -13,3 +13,4 @@ alert http2 any any -> any any (msg:"SURICATA HTTP2 invalid frame length"; flow:
alert http2 any any -> any any (msg:"SURICATA HTTP2 header frame with extra data"; flow:established; app-layer-event:http2.extra_header_data; classtype:protocol-command-decode; sid:2290005; rev:1;)
alert http2 any any -> any any (msg:"SURICATA HTTP2 too long frame data"; flow:established; app-layer-event:http2.long_frame_data; classtype:protocol-command-decode; sid:2290006; rev:1;)
alert http2 any any -> any any (msg:"SURICATA HTTP2 stream identifier reuse"; flow:established; app-layer-event:http2.stream_id_reuse; classtype:protocol-command-decode; sid:2290007; rev:1;)
alert http2 any any -> any any (msg:"SURICATA HTTP2 invalid HTTP1 settings during upgrade"; flow:established; app-layer-event:http2.invalid_http1_settings; classtype:protocol-command-decode; sid:2290008; rev:1;)

@ -16,11 +16,10 @@
*/
use super::http2::{
HTTP2Frame, HTTP2FrameTypeData, HTTP2State, HTTP2Transaction, HTTP2TransactionState,
HTTP2Event, HTTP2Frame, HTTP2FrameTypeData, HTTP2State, HTTP2Transaction, HTTP2TransactionState,
};
use super::parser;
use crate::core::STREAM_TOSERVER;
use crate::log::*;
use std::ffi::CStr;
use std::mem::transmute;
use std::str::FromStr;
@ -593,6 +592,141 @@ pub extern "C" fn rs_http2_tx_set_uri(state: &mut HTTP2State, buffer: *const u8,
http2_tx_set_header(state, ":path".as_bytes(), slice)
}
#[derive(Debug, PartialEq)]
pub enum Http2Base64Error {
InvalidBase64,
}
impl std::error::Error for Http2Base64Error {}
impl std::fmt::Display for Http2Base64Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "invalid base64")
}
}
fn http2_base64_map(input: u8) -> Result<u8, Http2Base64Error> {
match input {
43 => Ok(62), // +
47 => Ok(63), // /
48 => Ok(52), // 0
49 => Ok(53), // 1
50 => Ok(54), // 2
51 => Ok(55), // 3
52 => Ok(56), // 4
53 => Ok(57), // 5
54 => Ok(58), // 6
55 => Ok(59), // 7
56 => Ok(60), // 8
57 => Ok(61), // 9
65 => Ok(0), // A
66 => Ok(1), // B
67 => Ok(2), // C
68 => Ok(3), // D
69 => Ok(4), // E
70 => Ok(5), // F
71 => Ok(6), // G
72 => Ok(7), // H
73 => Ok(8), // I
74 => Ok(9), // J
75 => Ok(10), // K
76 => Ok(11), // L
77 => Ok(12), // M
78 => Ok(13), // N
79 => Ok(14), // O
80 => Ok(15), // P
81 => Ok(16), // Q
82 => Ok(17), // R
83 => Ok(18), // S
84 => Ok(19), // T
85 => Ok(20), // U
86 => Ok(21), // V
87 => Ok(22), // W
88 => Ok(23), // X
89 => Ok(24), // Y
90 => Ok(25), // Z
97 => Ok(26), // a
98 => Ok(27), // b
99 => Ok(28), // c
100 => Ok(29), // d
101 => Ok(30), // e
102 => Ok(31), // f
103 => Ok(32), // g
104 => Ok(33), // h
105 => Ok(34), // i
106 => Ok(35), // j
107 => Ok(36), // k
108 => Ok(37), // l
109 => Ok(38), // m
110 => Ok(39), // n
111 => Ok(40), // o
112 => Ok(41), // p
113 => Ok(42), // q
114 => Ok(43), // r
115 => Ok(44), // s
116 => Ok(45), // t
117 => Ok(46), // u
118 => Ok(47), // v
119 => Ok(48), // w
120 => Ok(49), // x
121 => Ok(50), // y
122 => Ok(51), // z
_ => Err(Http2Base64Error::InvalidBase64),
}
}
fn http2_decode_base64(input: &[u8]) -> Result<Vec<u8>, Http2Base64Error> {
if input.len() % 4 != 0 {
return Err(Http2Base64Error::InvalidBase64);
}
let mut r = vec![0; (input.len() * 3) / 4];
for i in 0..input.len() / 4 {
let i1 = http2_base64_map(input[4 * i])?;
let i2 = http2_base64_map(input[4 * i + 1])?;
let i3 = http2_base64_map(input[4 * i + 2])?;
let i4 = http2_base64_map(input[4 * i + 3])?;
r[3 * i] = (i1 << 2) | (i2 >> 4);
r[3 * i + 1] = (i2 << 4) | (i3 >> 2);
r[3 * i + 2] = (i3 << 6) | i4;
}
return Ok(r);
}
fn http2_tx_set_settings(state: &mut HTTP2State, input: &[u8]) {
match http2_decode_base64(input) {
Ok(dec) => {
if dec.len() % 6 != 0 {
state.set_event(HTTP2Event::InvalidHTTP1Settings);
}
let head = parser::HTTP2FrameHeader {
length: dec.len() as u32,
ftype: parser::HTTP2FrameType::SETTINGS as u8,
flags: 0,
reserved: 0,
stream_id: 0,
};
match parser::http2_parse_frame_settings(&dec) {
Ok((_, set)) => {
let txdata = HTTP2FrameTypeData::SETTINGS(set);
let tx = state.find_or_create_tx(&head, &txdata, STREAM_TOSERVER);
tx.frames_ts.push(HTTP2Frame {
header: head,
data: txdata,
});
}
Err(_) => {
state.set_event(HTTP2Event::InvalidHTTP1Settings);
}
}
}
Err(_) => {
state.set_event(HTTP2Event::InvalidHTTP1Settings);
}
}
}
#[no_mangle]
pub extern "C" fn rs_http2_tx_add_header(
state: &mut HTTP2State, name: *const u8, name_len: u32, value: *const u8, value_len: u32,
@ -600,7 +734,7 @@ pub extern "C" fn rs_http2_tx_add_header(
let slice_name = build_slice!(name, name_len as usize);
let slice_value = build_slice!(value, value_len as usize);
if slice_name == "HTTP2-Settings".as_bytes() {
SCLogNotice!("lol seetings TODO");
http2_tx_set_settings(state, slice_value)
} else {
http2_tx_set_header(state, slice_name, slice_value)
}

@ -246,6 +246,7 @@ pub enum HTTP2Event {
ExtraHeaderData,
LongFrameData,
StreamIdReuse,
InvalidHTTP1Settings,
}
impl HTTP2Event {
@ -259,6 +260,7 @@ impl HTTP2Event {
5 => Some(HTTP2Event::ExtraHeaderData),
6 => Some(HTTP2Event::LongFrameData),
7 => Some(HTTP2Event::StreamIdReuse),
8 => Some(HTTP2Event::InvalidHTTP1Settings),
_ => None,
}
}
@ -297,7 +299,7 @@ impl HTTP2State {
self.files.free();
}
fn set_event(&mut self, event: HTTP2Event) {
pub fn set_event(&mut self, event: HTTP2Event) {
let len = self.transactions.len();
if len == 0 {
return;
@ -1002,6 +1004,7 @@ pub extern "C" fn rs_http2_state_get_event_info(
"extra_header_data" => HTTP2Event::ExtraHeaderData as i32,
"long_frame_data" => HTTP2Event::LongFrameData as i32,
"stream_id_reuse" => HTTP2Event::StreamIdReuse as i32,
"invalid_http1_settings" => HTTP2Event::InvalidHTTP1Settings as i32,
_ => -1, // unknown event
}
}
@ -1029,6 +1032,7 @@ pub extern "C" fn rs_http2_state_get_event_info_by_id(
HTTP2Event::ExtraHeaderData => "extra_header_data\0",
HTTP2Event::LongFrameData => "long_frame_data\0",
HTTP2Event::StreamIdReuse => "stream_id_reuse\0",
HTTP2Event::InvalidHTTP1Settings => "invalid_http1_settings\0",
};
unsafe {
*event_name = estr.as_ptr() as *const std::os::raw::c_char;

Loading…
Cancel
Save