mirror of https://github.com/OISF/suricata
http2: initial support
parent
999af4f62a
commit
1422b18a99
@ -0,0 +1,15 @@
|
||||
# HTTP2 app layer event rules
|
||||
#
|
||||
# SID's fall in the 2290000+ range. See https://redmine.openinfosecfoundation.org/projects/suricata/wiki/AppLayer
|
||||
#
|
||||
# These sigs fire at most once per connection.
|
||||
#
|
||||
|
||||
alert http2 any any -> any any (msg:"SURICATA HTTP2 invalid frame header"; flow:established; app-layer-event:http2.invalid_frame_header; classtype:protocol-command-decode; sid:2290000; rev:1;)
|
||||
alert http2 any any -> any any (msg:"SURICATA HTTP2 invalid client magic"; flow:established; app-layer-event:http2.invalid_client_magic; classtype:protocol-command-decode; sid:2290001; rev:1;)
|
||||
alert http2 any any -> any any (msg:"SURICATA HTTP2 invalid frame data"; flow:established; app-layer-event:http2.invalid_frame_data; classtype:protocol-command-decode; sid:2290002; rev:1;)
|
||||
alert http2 any any -> any any (msg:"SURICATA HTTP2 invalid header"; flow:established; app-layer-event:http2.invalid_header; classtype:protocol-command-decode; sid:2290003; rev:1;)
|
||||
alert http2 any any -> any any (msg:"SURICATA HTTP2 invalid frame length"; flow:established; app-layer-event:http2.invalid_frame_length; classtype:protocol-command-decode; sid:2290004; rev:1;)
|
||||
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;)
|
||||
@ -0,0 +1,542 @@
|
||||
/* Copyright (C) 2020 Open Information Security Foundation
|
||||
*
|
||||
* You can copy, redistribute or modify this Program under the terms of
|
||||
* the GNU General Public License version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
use super::http2::{HTTP2FrameTypeData, HTTP2Transaction};
|
||||
use super::parser;
|
||||
use crate::core::STREAM_TOSERVER;
|
||||
use std::ffi::CStr;
|
||||
use std::mem::transmute;
|
||||
use std::str::FromStr;
|
||||
|
||||
fn http2_tx_has_frametype(
|
||||
tx: &mut HTTP2Transaction, direction: u8, value: u8,
|
||||
) -> std::os::raw::c_int {
|
||||
if direction & STREAM_TOSERVER != 0 {
|
||||
for i in 0..tx.frames_ts.len() {
|
||||
if tx.frames_ts[i].header.ftype as u8 == value {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i in 0..tx.frames_tc.len() {
|
||||
if tx.frames_tc[i].header.ftype as u8 == value {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_http2_tx_has_frametype(
|
||||
tx: *mut std::os::raw::c_void, direction: u8, value: u8,
|
||||
) -> std::os::raw::c_int {
|
||||
let tx = cast_pointer!(tx, HTTP2Transaction);
|
||||
return http2_tx_has_frametype(tx, direction, value);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn rs_http2_parse_frametype(
|
||||
str: *const std::os::raw::c_char,
|
||||
) -> std::os::raw::c_int {
|
||||
let ft_name: &CStr = CStr::from_ptr(str); //unsafe
|
||||
if let Ok(s) = ft_name.to_str() {
|
||||
if let Ok(x) = parser::HTTP2FrameType::from_str(s) {
|
||||
return x as i32;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
fn http2_tx_has_errorcode(
|
||||
tx: &mut HTTP2Transaction, direction: u8, code: u32,
|
||||
) -> std::os::raw::c_int {
|
||||
if direction & STREAM_TOSERVER != 0 {
|
||||
for i in 0..tx.frames_ts.len() {
|
||||
match tx.frames_ts[i].data {
|
||||
HTTP2FrameTypeData::GOAWAY(goaway) => {
|
||||
if goaway.errorcode == code {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
HTTP2FrameTypeData::RSTSTREAM(rst) => {
|
||||
if rst.errorcode == code {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i in 0..tx.frames_tc.len() {
|
||||
match tx.frames_tc[i].data {
|
||||
HTTP2FrameTypeData::GOAWAY(goaway) => {
|
||||
if goaway.errorcode as u32 == code {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
HTTP2FrameTypeData::RSTSTREAM(rst) => {
|
||||
if rst.errorcode as u32 == code {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_http2_tx_has_errorcode(
|
||||
tx: *mut std::os::raw::c_void, direction: u8, code: u32,
|
||||
) -> std::os::raw::c_int {
|
||||
let tx = cast_pointer!(tx, HTTP2Transaction);
|
||||
return http2_tx_has_errorcode(tx, direction, code);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn rs_http2_parse_errorcode(
|
||||
str: *const std::os::raw::c_char,
|
||||
) -> std::os::raw::c_int {
|
||||
let ft_name: &CStr = CStr::from_ptr(str); //unsafe
|
||||
if let Ok(s) = ft_name.to_str() {
|
||||
if let Ok(x) = parser::HTTP2ErrorCode::from_str(s) {
|
||||
return x as i32;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
fn http2_tx_get_next_priority(
|
||||
tx: &mut HTTP2Transaction, direction: u8, nb: u32,
|
||||
) -> std::os::raw::c_int {
|
||||
let mut pos = 0 as u32;
|
||||
if direction & STREAM_TOSERVER != 0 {
|
||||
for i in 0..tx.frames_ts.len() {
|
||||
match &tx.frames_ts[i].data {
|
||||
HTTP2FrameTypeData::PRIORITY(prio) => {
|
||||
if pos == nb {
|
||||
return prio.weight as i32;
|
||||
} else {
|
||||
pos = pos + 1;
|
||||
}
|
||||
}
|
||||
HTTP2FrameTypeData::HEADERS(hd) => {
|
||||
if let Some(prio) = hd.priority {
|
||||
if pos == nb {
|
||||
return prio.weight as i32;
|
||||
} else {
|
||||
pos = pos + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i in 0..tx.frames_tc.len() {
|
||||
match &tx.frames_tc[i].data {
|
||||
HTTP2FrameTypeData::PRIORITY(prio) => {
|
||||
if pos == nb {
|
||||
return prio.weight as i32;
|
||||
} else {
|
||||
pos = pos + 1;
|
||||
}
|
||||
}
|
||||
HTTP2FrameTypeData::HEADERS(hd) => {
|
||||
if let Some(prio) = hd.priority {
|
||||
if pos == nb {
|
||||
return prio.weight as i32;
|
||||
} else {
|
||||
pos = pos + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_http2_tx_get_next_priority(
|
||||
tx: *mut std::os::raw::c_void, direction: u8, nb: u32,
|
||||
) -> std::os::raw::c_int {
|
||||
let tx = cast_pointer!(tx, HTTP2Transaction);
|
||||
return http2_tx_get_next_priority(tx, direction, nb);
|
||||
}
|
||||
|
||||
fn http2_tx_get_next_window(
|
||||
tx: &mut HTTP2Transaction, direction: u8, nb: u32,
|
||||
) -> std::os::raw::c_int {
|
||||
let mut pos = 0 as u32;
|
||||
if direction & STREAM_TOSERVER != 0 {
|
||||
for i in 0..tx.frames_ts.len() {
|
||||
match tx.frames_ts[i].data {
|
||||
HTTP2FrameTypeData::WINDOWUPDATE(wu) => {
|
||||
if pos == nb {
|
||||
return wu.sizeinc as i32;
|
||||
} else {
|
||||
pos = pos + 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i in 0..tx.frames_tc.len() {
|
||||
match tx.frames_tc[i].data {
|
||||
HTTP2FrameTypeData::WINDOWUPDATE(wu) => {
|
||||
if pos == nb {
|
||||
return wu.sizeinc as i32;
|
||||
} else {
|
||||
pos = pos + 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_http2_tx_get_next_window(
|
||||
tx: *mut std::os::raw::c_void, direction: u8, nb: u32,
|
||||
) -> std::os::raw::c_int {
|
||||
let tx = cast_pointer!(tx, HTTP2Transaction);
|
||||
return http2_tx_get_next_window(tx, direction, nb);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn rs_http2_parse_settingsid(
|
||||
str: *const std::os::raw::c_char,
|
||||
) -> std::os::raw::c_int {
|
||||
let ft_name: &CStr = CStr::from_ptr(str); //unsafe
|
||||
if let Ok(s) = ft_name.to_str() {
|
||||
if let Ok(x) = parser::HTTP2SettingsId::from_str(s) {
|
||||
return x as i32;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn rs_http2_detect_settingsctx_parse(
|
||||
str: *const std::os::raw::c_char,
|
||||
) -> *mut std::os::raw::c_void {
|
||||
let ft_name: &CStr = CStr::from_ptr(str); //unsafe
|
||||
if let Ok(s) = ft_name.to_str() {
|
||||
if let Ok((_, ctx)) = parser::http2_parse_settingsctx(s) {
|
||||
let boxed = Box::new(ctx);
|
||||
return transmute(boxed); //unsafe
|
||||
}
|
||||
}
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn rs_http2_detect_settingsctx_free(ctx: *mut std::os::raw::c_void) {
|
||||
// Just unbox...
|
||||
let _ctx: Box<parser::DetectHTTP2settingsSigCtx> = transmute(ctx);
|
||||
}
|
||||
|
||||
fn http2_detect_settings_match(
|
||||
set: &Vec<parser::HTTP2FrameSettings>, ctx: &parser::DetectHTTP2settingsSigCtx,
|
||||
) -> std::os::raw::c_int {
|
||||
for i in 0..set.len() {
|
||||
if set[i].id == ctx.id {
|
||||
match &ctx.value {
|
||||
None => {
|
||||
return 1;
|
||||
}
|
||||
Some(x) => match x.mode {
|
||||
parser::DetectUintMode::DetectUintModeEqual => {
|
||||
if set[i].value == x.value {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
parser::DetectUintMode::DetectUintModeLt => {
|
||||
if set[i].value <= x.value {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
parser::DetectUintMode::DetectUintModeGt => {
|
||||
if set[i].value >= x.value {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
parser::DetectUintMode::DetectUintModeRange => {
|
||||
if set[i].value <= x.value && set[i].value >= x.valrange {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn http2_detect_settingsctx_match(
|
||||
ctx: &mut parser::DetectHTTP2settingsSigCtx, tx: &mut HTTP2Transaction, direction: u8,
|
||||
) -> std::os::raw::c_int {
|
||||
if direction & STREAM_TOSERVER != 0 {
|
||||
for i in 0..tx.frames_ts.len() {
|
||||
match &tx.frames_ts[i].data {
|
||||
HTTP2FrameTypeData::SETTINGS(set) => {
|
||||
if http2_detect_settings_match(&set, ctx) != 0 {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i in 0..tx.frames_tc.len() {
|
||||
match &tx.frames_tc[i].data {
|
||||
HTTP2FrameTypeData::SETTINGS(set) => {
|
||||
if http2_detect_settings_match(&set, ctx) != 0 {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_http2_detect_settingsctx_match(
|
||||
ctx: *const std::os::raw::c_void, tx: *mut std::os::raw::c_void, direction: u8,
|
||||
) -> std::os::raw::c_int {
|
||||
let ctx = cast_pointer!(ctx, parser::DetectHTTP2settingsSigCtx);
|
||||
let tx = cast_pointer!(tx, HTTP2Transaction);
|
||||
return http2_detect_settingsctx_match(ctx, tx, direction);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn rs_detect_u64_parse(
|
||||
str: *const std::os::raw::c_char,
|
||||
) -> *mut std::os::raw::c_void {
|
||||
let ft_name: &CStr = CStr::from_ptr(str); //unsafe
|
||||
if let Ok(s) = ft_name.to_str() {
|
||||
if let Ok((_, ctx)) = parser::detect_parse_u64(s) {
|
||||
let boxed = Box::new(ctx);
|
||||
return transmute(boxed); //unsafe
|
||||
}
|
||||
}
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn rs_detect_u64_free(ctx: *mut std::os::raw::c_void) {
|
||||
// Just unbox...
|
||||
let _ctx: Box<parser::DetectU64Data> = transmute(ctx);
|
||||
}
|
||||
|
||||
fn http2_detect_sizeupdate_match(
|
||||
hd: &parser::HTTP2FrameHeaders, ctx: &parser::DetectU64Data,
|
||||
) -> std::os::raw::c_int {
|
||||
for i in 0..hd.blocks.len() {
|
||||
match ctx.mode {
|
||||
parser::DetectUintMode::DetectUintModeEqual => {
|
||||
if hd.blocks[i].sizeupdate == ctx.value
|
||||
&& hd.blocks[i].error
|
||||
== parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
parser::DetectUintMode::DetectUintModeLt => {
|
||||
if hd.blocks[i].sizeupdate <= ctx.value
|
||||
&& hd.blocks[i].error
|
||||
== parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
parser::DetectUintMode::DetectUintModeGt => {
|
||||
if hd.blocks[i].sizeupdate >= ctx.value
|
||||
&& hd.blocks[i].error
|
||||
== parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
parser::DetectUintMode::DetectUintModeRange => {
|
||||
if hd.blocks[i].sizeupdate <= ctx.value
|
||||
&& hd.blocks[i].sizeupdate >= ctx.valrange
|
||||
&& hd.blocks[i].error
|
||||
== parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn http2_detect_sizeupdatectx_match(
|
||||
ctx: &mut parser::DetectU64Data, tx: &mut HTTP2Transaction, direction: u8,
|
||||
) -> std::os::raw::c_int {
|
||||
if direction & STREAM_TOSERVER != 0 {
|
||||
for i in 0..tx.frames_ts.len() {
|
||||
match &tx.frames_ts[i].data {
|
||||
HTTP2FrameTypeData::HEADERS(hd) => {
|
||||
if http2_detect_sizeupdate_match(&hd, ctx) != 0 {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i in 0..tx.frames_tc.len() {
|
||||
match &tx.frames_tc[i].data {
|
||||
HTTP2FrameTypeData::HEADERS(hd) => {
|
||||
if http2_detect_sizeupdate_match(&hd, ctx) != 0 {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_http2_detect_sizeupdatectx_match(
|
||||
ctx: *const std::os::raw::c_void, tx: *mut std::os::raw::c_void, direction: u8,
|
||||
) -> std::os::raw::c_int {
|
||||
let ctx = cast_pointer!(ctx, parser::DetectU64Data);
|
||||
let tx = cast_pointer!(tx, HTTP2Transaction);
|
||||
return http2_detect_sizeupdatectx_match(ctx, tx, direction);
|
||||
}
|
||||
|
||||
//TODOask better syntax between rs_http2_tx_get_header_name in argument
|
||||
// and rs_http2_detect_sizeupdatectx_match explicitly casting
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn rs_http2_tx_get_header_name(
|
||||
tx: &mut HTTP2Transaction, direction: u8, nb: u32, buffer: *mut *const u8, buffer_len: *mut u32,
|
||||
) -> u8 {
|
||||
let mut pos = 0 as u32;
|
||||
if direction & STREAM_TOSERVER != 0 {
|
||||
for i in 0..tx.frames_ts.len() {
|
||||
match &tx.frames_ts[i].data {
|
||||
HTTP2FrameTypeData::HEADERS(hd) => {
|
||||
if nb < pos + hd.blocks.len() as u32 {
|
||||
let value = &hd.blocks[(nb - pos) as usize].name;
|
||||
*buffer = value.as_ptr(); //unsafe
|
||||
*buffer_len = value.len() as u32;
|
||||
return 1;
|
||||
} else {
|
||||
pos = pos + hd.blocks.len() as u32;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i in 0..tx.frames_tc.len() {
|
||||
match &tx.frames_tc[i].data {
|
||||
HTTP2FrameTypeData::HEADERS(hd) => {
|
||||
if nb < pos + hd.blocks.len() as u32 {
|
||||
let value = &hd.blocks[(nb - pos) as usize].name;
|
||||
*buffer = value.as_ptr(); //unsafe
|
||||
*buffer_len = value.len() as u32;
|
||||
return 1;
|
||||
} else {
|
||||
pos = pos + hd.blocks.len() as u32;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn http2_escape_header(hd: &parser::HTTP2FrameHeaders, i: u32) -> Vec<u8> {
|
||||
//minimum size + 2 for escapes
|
||||
let normalsize = hd.blocks[i as usize].value.len() + 2 + hd.blocks[i as usize].name.len() + 2;
|
||||
let mut vec = Vec::with_capacity(normalsize);
|
||||
for j in 0..hd.blocks[i as usize].name.len() {
|
||||
vec.push(hd.blocks[i as usize].name[j]);
|
||||
if hd.blocks[i as usize].name[j] == ':' as u8 {
|
||||
vec.push(':' as u8);
|
||||
}
|
||||
}
|
||||
vec.push(':' as u8);
|
||||
vec.push(' ' as u8);
|
||||
for j in 0..hd.blocks[i as usize].value.len() {
|
||||
vec.push(hd.blocks[i as usize].value[j]);
|
||||
if hd.blocks[i as usize].value[j] == ':' as u8 {
|
||||
vec.push(':' as u8);
|
||||
}
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn rs_http2_tx_get_header(
|
||||
tx: &mut HTTP2Transaction, direction: u8, nb: u32, buffer: *mut *const u8, buffer_len: *mut u32,
|
||||
) -> u8 {
|
||||
let mut pos = 0 as u32;
|
||||
if direction & STREAM_TOSERVER != 0 {
|
||||
for i in 0..tx.frames_ts.len() {
|
||||
match &tx.frames_ts[i].data {
|
||||
HTTP2FrameTypeData::HEADERS(hd) => {
|
||||
if nb < pos + hd.blocks.len() as u32 {
|
||||
tx.escaped_tmp = http2_escape_header(&hd, nb - pos);
|
||||
let value = &tx.escaped_tmp;
|
||||
*buffer = value.as_ptr(); //unsafe
|
||||
*buffer_len = value.len() as u32;
|
||||
return 1;
|
||||
} else {
|
||||
pos = pos + hd.blocks.len() as u32;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i in 0..tx.frames_tc.len() {
|
||||
match &tx.frames_tc[i].data {
|
||||
HTTP2FrameTypeData::HEADERS(hd) => {
|
||||
if nb < pos + hd.blocks.len() as u32 {
|
||||
tx.escaped_tmp = http2_escape_header(&hd, nb - pos);
|
||||
let value = &tx.escaped_tmp;
|
||||
*buffer = value.as_ptr(); //unsafe
|
||||
*buffer_len = value.len() as u32;
|
||||
return 1;
|
||||
} else {
|
||||
pos = pos + hd.blocks.len() as u32;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
/* Copyright (C) 2020 Open Information Security Foundation
|
||||
*
|
||||
* You can copy, redistribute or modify this Program under the terms of
|
||||
* the GNU General Public License version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
use crate::core::*;
|
||||
use crate::filecontainer::*;
|
||||
|
||||
/// Wrapper around Suricata's internal file container logic.
|
||||
#[derive(Debug)]
|
||||
pub struct HTTP2Files {
|
||||
pub files_ts: FileContainer,
|
||||
pub files_tc: FileContainer,
|
||||
pub flags_ts: u16,
|
||||
pub flags_tc: u16,
|
||||
}
|
||||
|
||||
impl HTTP2Files {
|
||||
pub fn new() -> HTTP2Files {
|
||||
HTTP2Files {
|
||||
files_ts: FileContainer::default(),
|
||||
files_tc: FileContainer::default(),
|
||||
flags_ts: 0,
|
||||
flags_tc: 0,
|
||||
}
|
||||
}
|
||||
pub fn free(&mut self) {
|
||||
self.files_ts.free();
|
||||
self.files_tc.free();
|
||||
}
|
||||
|
||||
pub fn get(&mut self, direction: u8) -> (&mut FileContainer, u16) {
|
||||
if direction == STREAM_TOSERVER {
|
||||
(&mut self.files_ts, self.flags_ts)
|
||||
} else {
|
||||
(&mut self.files_tc, self.flags_tc)
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,504 @@
|
||||
/* Copyright (C) 2020 Open Information Security Foundation
|
||||
*
|
||||
* You can copy, redistribute or modify this Program under the terms of
|
||||
* the GNU General Public License version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
use nom::error::ErrorKind;
|
||||
use nom::Err;
|
||||
use nom::IResult;
|
||||
|
||||
fn http2_huffman_table_len5(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0 => Some(48),
|
||||
1 => Some(49),
|
||||
2 => Some(50),
|
||||
3 => Some(97),
|
||||
4 => Some(99),
|
||||
5 => Some(101),
|
||||
6 => Some(105),
|
||||
7 => Some(111),
|
||||
8 => Some(115),
|
||||
9 => Some(116),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len5<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(5u32), http2_huffman_table_len5) )
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len6(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0x14 => Some(32),
|
||||
0x15 => Some(37),
|
||||
0x16 => Some(45),
|
||||
0x17 => Some(46),
|
||||
0x18 => Some(47),
|
||||
0x19 => Some(51),
|
||||
0x1a => Some(52),
|
||||
0x1b => Some(53),
|
||||
0x1c => Some(54),
|
||||
0x1d => Some(55),
|
||||
0x1e => Some(56),
|
||||
0x1f => Some(57),
|
||||
0x20 => Some(61),
|
||||
0x21 => Some(65),
|
||||
0x22 => Some(95),
|
||||
0x23 => Some(98),
|
||||
0x24 => Some(100),
|
||||
0x25 => Some(102),
|
||||
0x26 => Some(103),
|
||||
0x27 => Some(104),
|
||||
0x28 => Some(108),
|
||||
0x29 => Some(109),
|
||||
0x2a => Some(110),
|
||||
0x2b => Some(112),
|
||||
0x2c => Some(114),
|
||||
0x2d => Some(117),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len6<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(6u32), http2_huffman_table_len6))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len7(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0x5c => Some(58),
|
||||
0x5d => Some(66),
|
||||
0x5e => Some(67),
|
||||
0x5f => Some(68),
|
||||
0x60 => Some(69),
|
||||
0x61 => Some(70),
|
||||
0x62 => Some(71),
|
||||
0x63 => Some(72),
|
||||
0x64 => Some(73),
|
||||
0x65 => Some(74),
|
||||
0x66 => Some(75),
|
||||
0x67 => Some(76),
|
||||
0x68 => Some(77),
|
||||
0x69 => Some(78),
|
||||
0x6a => Some(79),
|
||||
0x6b => Some(80),
|
||||
0x6c => Some(81),
|
||||
0x6d => Some(82),
|
||||
0x6e => Some(83),
|
||||
0x6f => Some(84),
|
||||
0x70 => Some(85),
|
||||
0x71 => Some(86),
|
||||
0x72 => Some(87),
|
||||
0x73 => Some(89),
|
||||
0x74 => Some(106),
|
||||
0x75 => Some(107),
|
||||
0x76 => Some(113),
|
||||
0x77 => Some(118),
|
||||
0x78 => Some(119),
|
||||
0x79 => Some(120),
|
||||
0x7a => Some(121),
|
||||
0x7b => Some(122),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len7<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(7u32), http2_huffman_table_len7))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len8(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0xf8 => Some(38),
|
||||
0xf9 => Some(42),
|
||||
0xfa => Some(44),
|
||||
0xfb => Some(59),
|
||||
0xfc => Some(88),
|
||||
0xfd => Some(90),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len8<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(8u32), http2_huffman_table_len8))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len10(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0x3f8 => Some(33),
|
||||
0x3f9 => Some(34),
|
||||
0x3fa => Some(40),
|
||||
0x3fb => Some(41),
|
||||
0x3fc => Some(63),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len10<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(10u32), http2_huffman_table_len10))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len11(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0x7fa => Some(39),
|
||||
0x7fb => Some(43),
|
||||
0x7fc => Some(124),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len11<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(11u32), http2_huffman_table_len11))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len12(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0xffa => Some(35),
|
||||
0xffb => Some(62),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len12<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(12u32), http2_huffman_table_len12))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len13(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0x1ff8 => Some(0),
|
||||
0x1ff9 => Some(36),
|
||||
0x1ffa => Some(64),
|
||||
0x1ffb => Some(91),
|
||||
0x1ffc => Some(93),
|
||||
0x1ffd => Some(126),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len13<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(13u32), http2_huffman_table_len13))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len14(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0x3ffc => Some(94),
|
||||
0x3ffd => Some(125),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len14<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(14u32), http2_huffman_table_len14))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len15(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0x7ffc => Some(60),
|
||||
0x7ffd => Some(96),
|
||||
0x7ffe => Some(123),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len15<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(15u32), http2_huffman_table_len15))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len19(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0x7fff0 => Some(92),
|
||||
0x7fff1 => Some(195),
|
||||
0x7fff2 => Some(208),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len19<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(19u32), http2_huffman_table_len19))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len20(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0xfffe6 => Some(128),
|
||||
0xfffe7 => Some(130),
|
||||
0xfffe8 => Some(131),
|
||||
0xfffe9 => Some(162),
|
||||
0xfffea => Some(184),
|
||||
0xfffeb => Some(194),
|
||||
0xfffec => Some(224),
|
||||
0xfffed => Some(226),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len20<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(20u32), http2_huffman_table_len20))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len21(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0x1fffdc => Some(153),
|
||||
0x1fffdd => Some(161),
|
||||
0x1fffde => Some(167),
|
||||
0x1fffdf => Some(172),
|
||||
0x1fffe0 => Some(176),
|
||||
0x1fffe1 => Some(177),
|
||||
0x1fffe2 => Some(179),
|
||||
0x1fffe3 => Some(209),
|
||||
0x1fffe4 => Some(216),
|
||||
0x1fffe5 => Some(217),
|
||||
0x1fffe6 => Some(227),
|
||||
0x1fffe7 => Some(229),
|
||||
0x1fffe8 => Some(230),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len21<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(21u32), http2_huffman_table_len21))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len22(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0x3fffd2 => Some(129),
|
||||
0x3fffd3 => Some(132),
|
||||
0x3fffd4 => Some(133),
|
||||
0x3fffd5 => Some(134),
|
||||
0x3fffd6 => Some(136),
|
||||
0x3fffd7 => Some(146),
|
||||
0x3fffd8 => Some(154),
|
||||
0x3fffd9 => Some(156),
|
||||
0x3fffda => Some(160),
|
||||
0x3fffdb => Some(163),
|
||||
0x3fffdc => Some(164),
|
||||
0x3fffdd => Some(169),
|
||||
0x3fffde => Some(170),
|
||||
0x3fffdf => Some(173),
|
||||
0x3fffe0 => Some(178),
|
||||
0x3fffe1 => Some(181),
|
||||
0x3fffe2 => Some(185),
|
||||
0x3fffe3 => Some(186),
|
||||
0x3fffe4 => Some(187),
|
||||
0x3fffe5 => Some(189),
|
||||
0x3fffe6 => Some(190),
|
||||
0x3fffe7 => Some(196),
|
||||
0x3fffe8 => Some(198),
|
||||
0x3fffe9 => Some(228),
|
||||
0x3fffea => Some(232),
|
||||
0x3fffeb => Some(233),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len22<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(22u32), http2_huffman_table_len22))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len23(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0x7fffd8 => Some(1),
|
||||
0x7fffd9 => Some(135),
|
||||
0x7fffda => Some(137),
|
||||
0x7fffdb => Some(138),
|
||||
0x7fffdc => Some(139),
|
||||
0x7fffdd => Some(140),
|
||||
0x7fffde => Some(141),
|
||||
0x7fffdf => Some(143),
|
||||
0x7fffe0 => Some(147),
|
||||
0x7fffe1 => Some(149),
|
||||
0x7fffe2 => Some(150),
|
||||
0x7fffe3 => Some(151),
|
||||
0x7fffe4 => Some(152),
|
||||
0x7fffe5 => Some(155),
|
||||
0x7fffe6 => Some(157),
|
||||
0x7fffe7 => Some(158),
|
||||
0x7fffe8 => Some(165),
|
||||
0x7fffe9 => Some(166),
|
||||
0x7fffea => Some(168),
|
||||
0x7fffeb => Some(174),
|
||||
0x7fffec => Some(175),
|
||||
0x7fffed => Some(180),
|
||||
0x7fffee => Some(182),
|
||||
0x7fffef => Some(183),
|
||||
0x7ffff0 => Some(188),
|
||||
0x7ffff1 => Some(191),
|
||||
0x7ffff2 => Some(197),
|
||||
0x7ffff3 => Some(231),
|
||||
0x7ffff4 => Some(239),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len23<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(23u32), http2_huffman_table_len23))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len24(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0xffffea => Some(9),
|
||||
0xffffeb => Some(142),
|
||||
0xffffec => Some(144),
|
||||
0xffffed => Some(145),
|
||||
0xffffee => Some(148),
|
||||
0xffffef => Some(159),
|
||||
0xfffff0 => Some(171),
|
||||
0xfffff1 => Some(206),
|
||||
0xfffff2 => Some(215),
|
||||
0xfffff3 => Some(225),
|
||||
0xfffff4 => Some(236),
|
||||
0xfffff5 => Some(237),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len24<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(24u32), http2_huffman_table_len24))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len25(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0x1ffffec => Some(199),
|
||||
0x1ffffed => Some(207),
|
||||
0x1ffffee => Some(234),
|
||||
0x1ffffef => Some(235),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len25<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(25u32), http2_huffman_table_len25))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len26(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0x3ffffe0 => Some(192),
|
||||
0x3ffffe1 => Some(193),
|
||||
0x3ffffe2 => Some(200),
|
||||
0x3ffffe3 => Some(201),
|
||||
0x3ffffe4 => Some(202),
|
||||
0x3ffffe5 => Some(205),
|
||||
0x3ffffe6 => Some(210),
|
||||
0x3ffffe7 => Some(213),
|
||||
0x3ffffe8 => Some(218),
|
||||
0x3ffffe9 => Some(219),
|
||||
0x3ffffea => Some(238),
|
||||
0x3ffffeb => Some(240),
|
||||
0x3ffffec => Some(242),
|
||||
0x3ffffed => Some(243),
|
||||
0x3ffffee => Some(255),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len26<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(26u32), http2_huffman_table_len26))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len27(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0x7ffffde => Some(203),
|
||||
0x7ffffdf => Some(204),
|
||||
0x7ffffe0 => Some(211),
|
||||
0x7ffffe1 => Some(212),
|
||||
0x7ffffe2 => Some(214),
|
||||
0x7ffffe3 => Some(221),
|
||||
0x7ffffe4 => Some(222),
|
||||
0x7ffffe5 => Some(223),
|
||||
0x7ffffe6 => Some(241),
|
||||
0x7ffffe7 => Some(244),
|
||||
0x7ffffe8 => Some(245),
|
||||
0x7ffffe9 => Some(246),
|
||||
0x7ffffea => Some(247),
|
||||
0x7ffffeb => Some(248),
|
||||
0x7ffffec => Some(250),
|
||||
0x7ffffed => Some(251),
|
||||
0x7ffffee => Some(252),
|
||||
0x7ffffef => Some(253),
|
||||
0x7fffff0 => Some(254),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len27<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(27u32), http2_huffman_table_len27))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len28(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0xfffffe2 => Some(2),
|
||||
0xfffffe3 => Some(3),
|
||||
0xfffffe4 => Some(4),
|
||||
0xfffffe5 => Some(5),
|
||||
0xfffffe6 => Some(6),
|
||||
0xfffffe7 => Some(7),
|
||||
0xfffffe8 => Some(8),
|
||||
0xfffffe9 => Some(11),
|
||||
0xfffffea => Some(12),
|
||||
0xfffffeb => Some(14),
|
||||
0xfffffec => Some(15),
|
||||
0xfffffed => Some(16),
|
||||
0xfffffee => Some(17),
|
||||
0xfffffef => Some(18),
|
||||
0xffffff0 => Some(19),
|
||||
0xffffff1 => Some(20),
|
||||
0xffffff2 => Some(21),
|
||||
0xffffff3 => Some(23),
|
||||
0xffffff4 => Some(24),
|
||||
0xffffff5 => Some(25),
|
||||
0xffffff6 => Some(26),
|
||||
0xffffff7 => Some(27),
|
||||
0xffffff8 => Some(28),
|
||||
0xffffff9 => Some(29),
|
||||
0xffffffa => Some(30),
|
||||
0xffffffb => Some(31),
|
||||
0xffffffc => Some(127),
|
||||
0xffffffd => Some(220),
|
||||
0xffffffe => Some(249),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len28<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(28u32), http2_huffman_table_len28))
|
||||
);
|
||||
|
||||
fn http2_huffman_table_len30(n: u32) -> Option<u8> {
|
||||
match n {
|
||||
0x3ffffffc => Some(10),
|
||||
0x3ffffffd => Some(13),
|
||||
0x3ffffffe => Some(22),
|
||||
// 0x3fffffff => Some(256),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
named!(http2_decode_huffman_len30<(&[u8], usize), u8>,
|
||||
complete!( map_opt!(take_bits!(30u32), http2_huffman_table_len30))
|
||||
);
|
||||
|
||||
//hack to end many0 even if some bits are remaining
|
||||
fn http2_decode_huffman_end(input: (&[u8], usize)) -> IResult<(&[u8], usize), u8> {
|
||||
return Err(Err::Error((input, ErrorKind::Eof)));
|
||||
}
|
||||
|
||||
//we could profile and optimize performance here
|
||||
named!(pub http2_decode_huffman<(&[u8], usize), u8>,
|
||||
alt!(http2_decode_huffman_len5 | http2_decode_huffman_len6 | http2_decode_huffman_len7 |
|
||||
http2_decode_huffman_len8 | http2_decode_huffman_len10 | http2_decode_huffman_len11 |
|
||||
http2_decode_huffman_len12 | http2_decode_huffman_len13 | http2_decode_huffman_len14 |
|
||||
http2_decode_huffman_len15 | http2_decode_huffman_len19 | http2_decode_huffman_len20 |
|
||||
http2_decode_huffman_len21 | http2_decode_huffman_len22 | http2_decode_huffman_len23 |
|
||||
http2_decode_huffman_len24 | http2_decode_huffman_len25 | http2_decode_huffman_len26 |
|
||||
http2_decode_huffman_len27 | http2_decode_huffman_len28 | http2_decode_huffman_len30 |
|
||||
http2_decode_huffman_end)
|
||||
);
|
||||
@ -0,0 +1,184 @@
|
||||
/* Copyright (C) 2020 Open Information Security Foundation
|
||||
*
|
||||
* You can copy, redistribute or modify this Program under the terms of
|
||||
* the GNU General Public License version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
use super::http2::{HTTP2Frame, HTTP2FrameTypeData, HTTP2Transaction};
|
||||
use super::parser;
|
||||
use crate::jsonbuilder::{JsonBuilder, JsonError};
|
||||
use std;
|
||||
|
||||
fn log_http2_headers(
|
||||
blocks: &Vec<parser::HTTP2FrameHeaderBlock>, js: &mut JsonBuilder,
|
||||
) -> Result<(), JsonError> {
|
||||
for j in 0..blocks.len() {
|
||||
js.start_object()?;
|
||||
match blocks[j].error {
|
||||
parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSuccess => {
|
||||
js.set_string_from_bytes("name", &blocks[j].name)?;
|
||||
js.set_string_from_bytes("value", &blocks[j].value)?;
|
||||
}
|
||||
parser::HTTP2HeaderDecodeStatus::HTTP2HeaderDecodeSizeUpdate => {
|
||||
js.set_uint("table_size_update", blocks[j].sizeupdate)?;
|
||||
}
|
||||
_ => {
|
||||
js.set_string("error", &blocks[j].error.to_string())?;
|
||||
}
|
||||
}
|
||||
js.close()?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn log_http2_frames(frames: &Vec<HTTP2Frame>, js: &mut JsonBuilder) -> Result<bool, JsonError> {
|
||||
let mut has_settings = false;
|
||||
for i in 0..frames.len() {
|
||||
if let HTTP2FrameTypeData::SETTINGS(set) = &frames[i].data {
|
||||
if !has_settings {
|
||||
js.open_array("settings")?;
|
||||
has_settings = true;
|
||||
}
|
||||
for j in 0..set.len() {
|
||||
js.start_object()?;
|
||||
js.set_string("settings_id", &set[j].id.to_string())?;
|
||||
js.set_uint("settings_value", set[j].value as u64)?;
|
||||
js.close()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
if has_settings {
|
||||
js.close()?;
|
||||
}
|
||||
|
||||
let mut has_headers = false;
|
||||
for i in 0..frames.len() {
|
||||
match &frames[i].data {
|
||||
HTTP2FrameTypeData::HEADERS(hd) => {
|
||||
if !has_headers {
|
||||
js.open_array("headers")?;
|
||||
has_headers = true;
|
||||
}
|
||||
log_http2_headers(&hd.blocks, js)?;
|
||||
}
|
||||
HTTP2FrameTypeData::PUSHPROMISE(hd) => {
|
||||
if !has_headers {
|
||||
js.open_array("headers")?;
|
||||
has_headers = true;
|
||||
}
|
||||
log_http2_headers(&hd.blocks, js)?;
|
||||
}
|
||||
HTTP2FrameTypeData::CONTINUATION(hd) => {
|
||||
if !has_headers {
|
||||
js.open_array("headers")?;
|
||||
has_headers = true;
|
||||
}
|
||||
log_http2_headers(&hd.blocks, js)?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if has_headers {
|
||||
js.close()?;
|
||||
}
|
||||
|
||||
let mut has_error_code = false;
|
||||
let mut has_priority = false;
|
||||
let mut has_multiple = false;
|
||||
for i in 0..frames.len() {
|
||||
match &frames[i].data {
|
||||
HTTP2FrameTypeData::GOAWAY(goaway) => {
|
||||
if !has_error_code {
|
||||
let errcode: Option<parser::HTTP2ErrorCode> =
|
||||
num::FromPrimitive::from_u32(goaway.errorcode);
|
||||
match errcode {
|
||||
Some(errstr) => {
|
||||
js.set_string("error_code", &errstr.to_string())?;
|
||||
}
|
||||
None => {
|
||||
//use uint32
|
||||
js.set_string("error_code", &goaway.errorcode.to_string())?;
|
||||
}
|
||||
}
|
||||
has_error_code = true;
|
||||
} else if !has_multiple {
|
||||
js.set_string("has_multiple", "error_code")?;
|
||||
has_multiple = true;
|
||||
}
|
||||
}
|
||||
HTTP2FrameTypeData::RSTSTREAM(rst) => {
|
||||
if !has_error_code {
|
||||
let errcode: Option<parser::HTTP2ErrorCode> =
|
||||
num::FromPrimitive::from_u32(rst.errorcode);
|
||||
match errcode {
|
||||
Some(errstr) => {
|
||||
js.set_string("error_code", &errstr.to_string())?;
|
||||
}
|
||||
None => {
|
||||
//use uint32
|
||||
js.set_string("error_code", &rst.errorcode.to_string())?;
|
||||
}
|
||||
}
|
||||
has_error_code = true;
|
||||
} else if !has_multiple {
|
||||
js.set_string("has_multiple", "error_code")?;
|
||||
has_multiple = true;
|
||||
}
|
||||
}
|
||||
HTTP2FrameTypeData::PRIORITY(priority) => {
|
||||
if !has_priority {
|
||||
js.set_uint("priority", priority.weight as u64)?;
|
||||
has_priority = true;
|
||||
} else if !has_multiple {
|
||||
js.set_string("has_multiple", "priority")?;
|
||||
has_multiple = true;
|
||||
}
|
||||
}
|
||||
HTTP2FrameTypeData::HEADERS(hd) => {
|
||||
if let Some(ref priority) = hd.priority {
|
||||
if !has_priority {
|
||||
js.set_uint("priority", priority.weight as u64)?;
|
||||
has_priority = true;
|
||||
} else if !has_multiple {
|
||||
js.set_string("has_multiple", "priority")?;
|
||||
has_multiple = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
return Ok(has_settings || has_headers || has_error_code || has_priority);
|
||||
}
|
||||
|
||||
fn log_http2(tx: &HTTP2Transaction, js: &mut JsonBuilder) -> Result<bool, JsonError> {
|
||||
js.set_uint("stream_id", tx.stream_id as u64)?;
|
||||
js.open_object("request")?;
|
||||
let has_request = log_http2_frames(&tx.frames_ts, js)?;
|
||||
js.close()?;
|
||||
js.open_object("response")?;
|
||||
let has_response = log_http2_frames(&tx.frames_tc, js)?;
|
||||
js.close()?;
|
||||
|
||||
return Ok(has_request || has_response);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_http2_log_json(tx: *mut std::os::raw::c_void, js: &mut JsonBuilder) -> bool {
|
||||
let tx = cast_pointer!(tx, HTTP2Transaction);
|
||||
if let Ok(x) = log_http2(tx, js) {
|
||||
return x;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
/* Copyright (C) 2020 Open Information Security Foundation
|
||||
*
|
||||
* You can copy, redistribute or modify this Program under the terms of
|
||||
* the GNU General Public License version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
pub mod detect;
|
||||
pub mod files;
|
||||
pub mod http2;
|
||||
mod huffman;
|
||||
pub mod logger;
|
||||
mod parser;
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,71 @@
|
||||
/* Copyright (C) 2020 Open Information Security Foundation
|
||||
*
|
||||
* You can copy, redistribute or modify this Program under the terms of
|
||||
* the GNU General Public License version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Philippe Antoine <p.antoine@catenacyber.fr>
|
||||
*
|
||||
* Parser for HTTP2, RFC 7540
|
||||
*/
|
||||
|
||||
#include "suricata-common.h"
|
||||
#include "stream.h"
|
||||
#include "conf.h"
|
||||
|
||||
#include "util-unittest.h"
|
||||
|
||||
#include "app-layer-detect-proto.h"
|
||||
#include "app-layer-parser.h"
|
||||
|
||||
#include "app-layer-http2.h"
|
||||
#include "rust.h"
|
||||
|
||||
static int HTTP2RegisterPatternsForProtocolDetection(void)
|
||||
{
|
||||
/* Using the 24 bytes pattern makes AppLayerTest09 fail/leak
|
||||
* The complete pattern is "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
|
||||
*/
|
||||
if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_HTTP2,
|
||||
"PRI * HTTP/2.0\r\n",
|
||||
16, 0, STREAM_TOSERVER) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER;
|
||||
static SuricataFileContext sfc = { &sbcfg };
|
||||
|
||||
void RegisterHTTP2Parsers(void)
|
||||
{
|
||||
const char *proto_name = "http2";
|
||||
|
||||
if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
|
||||
AppLayerProtoDetectRegisterProtocol(ALPROTO_HTTP2, proto_name);
|
||||
if (HTTP2RegisterPatternsForProtocolDetection() < 0)
|
||||
return;
|
||||
|
||||
rs_http2_init(&sfc);
|
||||
rs_http2_register_parser();
|
||||
}
|
||||
|
||||
#ifdef UNITTESTS
|
||||
//TODOask HTTP2ParserRegisterTests();
|
||||
#endif
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
/* Copyright (C) 2020 Open Information Security Foundation
|
||||
*
|
||||
* You can copy, redistribute or modify this Program under the terms of
|
||||
* the GNU General Public License version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Philippe Antoine <p.antoine@catenacyber.fr>
|
||||
*/
|
||||
|
||||
#ifndef __APP_LAYER_HTTP2_H__
|
||||
#define __APP_LAYER_HTTP2_H__
|
||||
|
||||
void RegisterHTTP2Parsers(void);
|
||||
|
||||
#endif /* __APP_LAYER_HTTP2_H__ */
|
||||
@ -0,0 +1,984 @@
|
||||
/* Copyright (C) 2020 Open Information Security Foundation
|
||||
*
|
||||
* You can copy, redistribute or modify this Program under the terms of
|
||||
* the GNU General Public License version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Philippe Antoine <p.antoine@catenacyber.fr>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "suricata-common.h"
|
||||
|
||||
#include "detect.h"
|
||||
#include "detect-parse.h"
|
||||
#include "detect-engine.h"
|
||||
#include "detect-engine-uint.h"
|
||||
#include "detect-engine-mpm.h"
|
||||
#include "detect-engine-prefilter.h"
|
||||
#include "detect-engine-content-inspection.h"
|
||||
|
||||
#include "detect-http2.h"
|
||||
#include "util-byte.h"
|
||||
#include "rust.h"
|
||||
|
||||
#ifdef UNITTESTS
|
||||
void DetectHTTP2frameTypeRegisterTests (void);
|
||||
void DetectHTTP2errorCodeRegisterTests (void);
|
||||
void DetectHTTP2priorityRegisterTests (void);
|
||||
void DetectHTTP2windowRegisterTests (void);
|
||||
void DetectHTTP2settingsRegisterTests (void);
|
||||
void DetectHTTP2sizeUpdateRegisterTests (void);
|
||||
#endif
|
||||
|
||||
/* prototypes */
|
||||
static int DetectHTTP2frametypeMatch(DetectEngineThreadCtx *det_ctx,
|
||||
Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
|
||||
const SigMatchCtx *ctx);
|
||||
static int DetectHTTP2frametypeSetup (DetectEngineCtx *, Signature *, const char *);
|
||||
void DetectHTTP2frametypeFree (DetectEngineCtx *, void *);
|
||||
|
||||
static int DetectHTTP2errorcodeMatch(DetectEngineThreadCtx *det_ctx,
|
||||
Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
|
||||
const SigMatchCtx *ctx);
|
||||
static int DetectHTTP2errorcodeSetup (DetectEngineCtx *, Signature *, const char *);
|
||||
void DetectHTTP2errorcodeFree (DetectEngineCtx *, void *);
|
||||
|
||||
static int DetectHTTP2priorityMatch(DetectEngineThreadCtx *det_ctx,
|
||||
Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
|
||||
const SigMatchCtx *ctx);
|
||||
static int DetectHTTP2prioritySetup (DetectEngineCtx *, Signature *, const char *);
|
||||
void DetectHTTP2priorityFree (DetectEngineCtx *, void *);
|
||||
|
||||
static int DetectHTTP2windowMatch(DetectEngineThreadCtx *det_ctx,
|
||||
Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
|
||||
const SigMatchCtx *ctx);
|
||||
static int DetectHTTP2windowSetup (DetectEngineCtx *, Signature *, const char *);
|
||||
void DetectHTTP2windowFree (DetectEngineCtx *, void *);
|
||||
|
||||
static int DetectHTTP2sizeUpdateMatch(DetectEngineThreadCtx *det_ctx,
|
||||
Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
|
||||
const SigMatchCtx *ctx);
|
||||
static int DetectHTTP2sizeUpdateSetup (DetectEngineCtx *, Signature *, const char *);
|
||||
void DetectHTTP2sizeUpdateFree (DetectEngineCtx *, void *);
|
||||
|
||||
static int DetectHTTP2settingsMatch(DetectEngineThreadCtx *det_ctx,
|
||||
Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
|
||||
const SigMatchCtx *ctx);
|
||||
static int DetectHTTP2settingsSetup (DetectEngineCtx *, Signature *, const char *);
|
||||
void DetectHTTP2settingsFree (DetectEngineCtx *, void *);
|
||||
|
||||
static int DetectHTTP2headerNameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg);
|
||||
static int PrefilterMpmHttp2HeaderNameRegister(DetectEngineCtx *de_ctx,
|
||||
SigGroupHead *sgh, MpmCtx *mpm_ctx,
|
||||
const DetectBufferMpmRegistery *mpm_reg, int list_id);
|
||||
static int DetectEngineInspectHttp2HeaderName(
|
||||
DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
|
||||
const DetectEngineAppInspectionEngine *engine,
|
||||
const Signature *s,
|
||||
Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id);
|
||||
|
||||
static int DetectHTTP2headerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg);
|
||||
static int PrefilterMpmHttp2HeaderRegister(DetectEngineCtx *de_ctx,
|
||||
SigGroupHead *sgh, MpmCtx *mpm_ctx,
|
||||
const DetectBufferMpmRegistery *mpm_reg, int list_id);
|
||||
static int DetectEngineInspectHttp2Header(
|
||||
DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
|
||||
const DetectEngineAppInspectionEngine *engine,
|
||||
const Signature *s,
|
||||
Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id);
|
||||
static bool DetectHttp2HeaderValidateCallback(const Signature *s, const char **sigerror);
|
||||
|
||||
#ifdef UNITTESTS
|
||||
void DetectHTTP2RegisterTests (void);
|
||||
#endif
|
||||
|
||||
static int g_http2_match_buffer_id = 0;
|
||||
static int g_http2_header_name_buffer_id = 0;
|
||||
static int g_http2_header_buffer_id = 0;
|
||||
|
||||
static int DetectEngineInspectHTTP2(ThreadVars *tv, DetectEngineCtx *de_ctx,
|
||||
DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd,
|
||||
Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
|
||||
{
|
||||
return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd,
|
||||
f, flags, alstate, txv, tx_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Registration function for HTTP2 keywords
|
||||
*/
|
||||
|
||||
void DetectHttp2Register(void)
|
||||
{
|
||||
sigmatch_table[DETECT_HTTP2_FRAMETYPE].name = "http2.frametype";
|
||||
sigmatch_table[DETECT_HTTP2_FRAMETYPE].desc = "match on HTTP2 frame type field";
|
||||
sigmatch_table[DETECT_HTTP2_FRAMETYPE].url = "/rules/http2-keywords.html#frametype";
|
||||
sigmatch_table[DETECT_HTTP2_FRAMETYPE].Match = NULL;
|
||||
sigmatch_table[DETECT_HTTP2_FRAMETYPE].AppLayerTxMatch = DetectHTTP2frametypeMatch;
|
||||
sigmatch_table[DETECT_HTTP2_FRAMETYPE].Setup = DetectHTTP2frametypeSetup;
|
||||
sigmatch_table[DETECT_HTTP2_FRAMETYPE].Free = DetectHTTP2frametypeFree;
|
||||
#ifdef UNITTESTS
|
||||
sigmatch_table[DETECT_HTTP2_FRAMETYPE].RegisterTests = DetectHTTP2frameTypeRegisterTests;
|
||||
#endif
|
||||
|
||||
sigmatch_table[DETECT_HTTP2_ERRORCODE].name = "http2.errorcode";
|
||||
sigmatch_table[DETECT_HTTP2_ERRORCODE].desc = "match on HTTP2 error code field";
|
||||
sigmatch_table[DETECT_HTTP2_ERRORCODE].url = "/rules/http2-keywords.html#errorcode";
|
||||
sigmatch_table[DETECT_HTTP2_ERRORCODE].Match = NULL;
|
||||
sigmatch_table[DETECT_HTTP2_ERRORCODE].AppLayerTxMatch = DetectHTTP2errorcodeMatch;
|
||||
sigmatch_table[DETECT_HTTP2_ERRORCODE].Setup = DetectHTTP2errorcodeSetup;
|
||||
sigmatch_table[DETECT_HTTP2_ERRORCODE].Free = DetectHTTP2errorcodeFree;
|
||||
#ifdef UNITTESTS
|
||||
sigmatch_table[DETECT_HTTP2_ERRORCODE].RegisterTests = DetectHTTP2errorCodeRegisterTests;
|
||||
#endif
|
||||
|
||||
sigmatch_table[DETECT_HTTP2_PRIORITY].name = "http2.priority";
|
||||
sigmatch_table[DETECT_HTTP2_PRIORITY].desc = "match on HTTP2 priority weight field";
|
||||
sigmatch_table[DETECT_HTTP2_PRIORITY].url = "/rules/http2-keywords.html#priority";
|
||||
sigmatch_table[DETECT_HTTP2_PRIORITY].Match = NULL;
|
||||
sigmatch_table[DETECT_HTTP2_PRIORITY].AppLayerTxMatch = DetectHTTP2priorityMatch;
|
||||
sigmatch_table[DETECT_HTTP2_PRIORITY].Setup = DetectHTTP2prioritySetup;
|
||||
sigmatch_table[DETECT_HTTP2_PRIORITY].Free = DetectHTTP2priorityFree;
|
||||
#ifdef UNITTESTS
|
||||
sigmatch_table[DETECT_HTTP2_PRIORITY].RegisterTests = DetectHTTP2priorityRegisterTests;
|
||||
#endif
|
||||
|
||||
sigmatch_table[DETECT_HTTP2_WINDOW].name = "http2.window";
|
||||
sigmatch_table[DETECT_HTTP2_WINDOW].desc = "match on HTTP2 window update size increment field";
|
||||
sigmatch_table[DETECT_HTTP2_WINDOW].url = "/rules/http2-keywords.html#window";
|
||||
sigmatch_table[DETECT_HTTP2_WINDOW].Match = NULL;
|
||||
sigmatch_table[DETECT_HTTP2_WINDOW].AppLayerTxMatch = DetectHTTP2windowMatch;
|
||||
sigmatch_table[DETECT_HTTP2_WINDOW].Setup = DetectHTTP2windowSetup;
|
||||
sigmatch_table[DETECT_HTTP2_WINDOW].Free = DetectHTTP2windowFree;
|
||||
#ifdef UNITTESTS
|
||||
sigmatch_table[DETECT_HTTP2_WINDOW].RegisterTests = DetectHTTP2windowRegisterTests;
|
||||
#endif
|
||||
|
||||
sigmatch_table[DETECT_HTTP2_SIZEUPDATE].name = "http2.size_update";
|
||||
sigmatch_table[DETECT_HTTP2_SIZEUPDATE].desc = "match on HTTP2 dynamic headers table size update";
|
||||
sigmatch_table[DETECT_HTTP2_SIZEUPDATE].url = "/rules/http2-keywords.html#sizeupdate";
|
||||
sigmatch_table[DETECT_HTTP2_SIZEUPDATE].Match = NULL;
|
||||
sigmatch_table[DETECT_HTTP2_SIZEUPDATE].AppLayerTxMatch = DetectHTTP2sizeUpdateMatch;
|
||||
sigmatch_table[DETECT_HTTP2_SIZEUPDATE].Setup = DetectHTTP2sizeUpdateSetup;
|
||||
sigmatch_table[DETECT_HTTP2_SIZEUPDATE].Free = DetectHTTP2sizeUpdateFree;
|
||||
#ifdef UNITTESTS
|
||||
sigmatch_table[DETECT_HTTP2_SIZEUPDATE].RegisterTests = DetectHTTP2sizeUpdateRegisterTests;
|
||||
#endif
|
||||
|
||||
sigmatch_table[DETECT_HTTP2_SETTINGS].name = "http2.settings";
|
||||
sigmatch_table[DETECT_HTTP2_SETTINGS].desc = "match on HTTP2 settings identifier and value fields";
|
||||
sigmatch_table[DETECT_HTTP2_SETTINGS].url = "/rules/http2-keywords.html#settings";
|
||||
sigmatch_table[DETECT_HTTP2_SETTINGS].Match = NULL;
|
||||
sigmatch_table[DETECT_HTTP2_SETTINGS].AppLayerTxMatch = DetectHTTP2settingsMatch;
|
||||
sigmatch_table[DETECT_HTTP2_SETTINGS].Setup = DetectHTTP2settingsSetup;
|
||||
sigmatch_table[DETECT_HTTP2_SETTINGS].Free = DetectHTTP2settingsFree;
|
||||
#ifdef UNITTESTS
|
||||
sigmatch_table[DETECT_HTTP2_SETTINGS].RegisterTests = DetectHTTP2settingsRegisterTests;
|
||||
#endif
|
||||
|
||||
sigmatch_table[DETECT_HTTP2_HEADERNAME].name = "http2.header_name";
|
||||
sigmatch_table[DETECT_HTTP2_HEADERNAME].desc = "sticky buffer to match on one HTTP2 header name";
|
||||
sigmatch_table[DETECT_HTTP2_HEADERNAME].url = "/rules/http2-keywords.html#header_name";
|
||||
sigmatch_table[DETECT_HTTP2_HEADERNAME].Setup = DetectHTTP2headerNameSetup;
|
||||
sigmatch_table[DETECT_HTTP2_HEADERNAME].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
|
||||
|
||||
DetectAppLayerMpmRegister2("http2_header_name", SIG_FLAG_TOCLIENT, 2,
|
||||
PrefilterMpmHttp2HeaderNameRegister, NULL,
|
||||
ALPROTO_HTTP2, HTTP2StateOpen);
|
||||
DetectAppLayerInspectEngineRegister2("http2_header_name",
|
||||
ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, HTTP2StateOpen,
|
||||
DetectEngineInspectHttp2HeaderName, NULL);
|
||||
DetectAppLayerMpmRegister2("http2_header_name", SIG_FLAG_TOSERVER, 2,
|
||||
PrefilterMpmHttp2HeaderNameRegister, NULL,
|
||||
ALPROTO_HTTP2, HTTP2StateOpen);
|
||||
DetectAppLayerInspectEngineRegister2("http2_header_name",
|
||||
ALPROTO_HTTP2, SIG_FLAG_TOSERVER, HTTP2StateOpen,
|
||||
DetectEngineInspectHttp2HeaderName, NULL);
|
||||
|
||||
DetectBufferTypeSetDescriptionByName("http2_header_name",
|
||||
"HTTP2 header name");
|
||||
g_http2_header_name_buffer_id = DetectBufferTypeGetByName("http2_header_name");
|
||||
|
||||
sigmatch_table[DETECT_HTTP2_HEADER].name = "http2.header";
|
||||
sigmatch_table[DETECT_HTTP2_HEADER].desc = "sticky buffer to match on one HTTP2 header name and value";
|
||||
sigmatch_table[DETECT_HTTP2_HEADER].url = "/rules/http2-keywords.html#header";
|
||||
sigmatch_table[DETECT_HTTP2_HEADER].Setup = DetectHTTP2headerSetup;
|
||||
sigmatch_table[DETECT_HTTP2_HEADER].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
|
||||
|
||||
DetectAppLayerMpmRegister2("http2_header", SIG_FLAG_TOCLIENT, 2,
|
||||
PrefilterMpmHttp2HeaderRegister, NULL,
|
||||
ALPROTO_HTTP2, HTTP2StateOpen);
|
||||
DetectAppLayerInspectEngineRegister2("http2_header",
|
||||
ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, HTTP2StateOpen,
|
||||
DetectEngineInspectHttp2Header, NULL);
|
||||
DetectAppLayerMpmRegister2("http2_header", SIG_FLAG_TOSERVER, 2,
|
||||
PrefilterMpmHttp2HeaderRegister, NULL,
|
||||
ALPROTO_HTTP2, HTTP2StateOpen);
|
||||
DetectAppLayerInspectEngineRegister2("http2_header",
|
||||
ALPROTO_HTTP2, SIG_FLAG_TOSERVER, HTTP2StateOpen,
|
||||
DetectEngineInspectHttp2Header, NULL);
|
||||
|
||||
DetectBufferTypeSetDescriptionByName("http2_header",
|
||||
"HTTP2 header name and value");
|
||||
DetectBufferTypeRegisterValidateCallback("http2_header", DetectHttp2HeaderValidateCallback);
|
||||
g_http2_header_buffer_id = DetectBufferTypeGetByName("http2_header");
|
||||
|
||||
DetectAppLayerInspectEngineRegister("http2",
|
||||
ALPROTO_HTTP2, SIG_FLAG_TOSERVER, 0,
|
||||
DetectEngineInspectHTTP2);
|
||||
DetectAppLayerInspectEngineRegister("http2",
|
||||
ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, 0,
|
||||
DetectEngineInspectHTTP2);
|
||||
|
||||
g_http2_match_buffer_id = DetectBufferTypeRegister("http2");
|
||||
DetectUintRegister();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief This function is used to match HTTP2 frame type rule option on a transaction with those passed via http2.frametype:
|
||||
*
|
||||
* \retval 0 no match
|
||||
* \retval 1 match
|
||||
*/
|
||||
static int DetectHTTP2frametypeMatch(DetectEngineThreadCtx *det_ctx,
|
||||
Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
|
||||
const SigMatchCtx *ctx)
|
||||
|
||||
{
|
||||
uint8_t *detect = (uint8_t *)ctx;
|
||||
|
||||
return rs_http2_tx_has_frametype(txv, flags, *detect);
|
||||
}
|
||||
|
||||
static int DetectHTTP2FuncParseFrameType(const char *str, uint8_t *ft)
|
||||
{
|
||||
// first parse numeric value
|
||||
if (ByteExtractStringUint8(ft, 10, strlen(str), str) >= 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// it it failed so far, parse string value from enumeration
|
||||
int r = rs_http2_parse_frametype(str);
|
||||
if (r >= 0) {
|
||||
*ft = r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief this function is used to attach the parsed http2.frametype data into the current signature
|
||||
*
|
||||
* \param de_ctx pointer to the Detection Engine Context
|
||||
* \param s pointer to the Current Signature
|
||||
* \param str pointer to the user provided http2.frametype options
|
||||
*
|
||||
* \retval 0 on Success
|
||||
* \retval -1 on Failure
|
||||
*/
|
||||
static int DetectHTTP2frametypeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
|
||||
{
|
||||
uint8_t frame_type;
|
||||
|
||||
if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
|
||||
return -1;
|
||||
|
||||
if (!DetectHTTP2FuncParseFrameType(str, &frame_type)) {
|
||||
SCLogError(SC_ERR_INVALID_SIGNATURE,
|
||||
"Invalid argument \"%s\" supplied to http2.frametype keyword.", str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t *http2ft = SCCalloc(1, sizeof(uint8_t));
|
||||
if (http2ft == NULL)
|
||||
return -1;
|
||||
*http2ft = frame_type;
|
||||
|
||||
SigMatch *sm = SigMatchAlloc();
|
||||
if (sm == NULL) {
|
||||
DetectHTTP2frametypeFree(NULL, http2ft);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sm->type = DETECT_HTTP2_FRAMETYPE;
|
||||
sm->ctx = (SigMatchCtx *)http2ft;
|
||||
|
||||
SigMatchAppendSMToList(s, sm, g_http2_match_buffer_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief this function will free memory associated with uint8_t
|
||||
*
|
||||
* \param ptr pointer to uint8_t
|
||||
*/
|
||||
void DetectHTTP2frametypeFree(DetectEngineCtx *de_ctx, void *ptr)
|
||||
{
|
||||
SCFree(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief This function is used to match HTTP2 error code rule option on a transaction with those passed via http2.errorcode:
|
||||
*
|
||||
* \retval 0 no match
|
||||
* \retval 1 match
|
||||
*/
|
||||
static int DetectHTTP2errorcodeMatch(DetectEngineThreadCtx *det_ctx,
|
||||
Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
|
||||
const SigMatchCtx *ctx)
|
||||
|
||||
{
|
||||
uint32_t *detect = (uint32_t *)ctx;
|
||||
|
||||
return rs_http2_tx_has_errorcode(txv, flags, *detect);
|
||||
//TODOask handle negation rules
|
||||
}
|
||||
|
||||
static int DetectHTTP2FuncParseErrorCode(const char *str, uint32_t *ec)
|
||||
{
|
||||
// first parse numeric value
|
||||
if (ByteExtractStringUint32(ec, 10, strlen(str), str) >= 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// it it failed so far, parse string value from enumeration
|
||||
int r = rs_http2_parse_errorcode(str);
|
||||
if (r >= 0) {
|
||||
*ec = r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief this function is used to attach the parsed http2.errorcode data into the current signature
|
||||
*
|
||||
* \param de_ctx pointer to the Detection Engine Context
|
||||
* \param s pointer to the Current Signature
|
||||
* \param str pointer to the user provided http2.errorcode options
|
||||
*
|
||||
* \retval 0 on Success
|
||||
* \retval -1 on Failure
|
||||
*/
|
||||
static int DetectHTTP2errorcodeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
|
||||
{
|
||||
uint32_t error_code;
|
||||
|
||||
if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
|
||||
return -1;
|
||||
|
||||
if (!DetectHTTP2FuncParseErrorCode(str, &error_code)) {
|
||||
SCLogError(SC_ERR_INVALID_SIGNATURE,
|
||||
"Invalid argument \"%s\" supplied to http2.errorcode keyword.", str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t *http2ec = SCCalloc(1, sizeof(uint32_t));
|
||||
if (http2ec == NULL)
|
||||
return -1;
|
||||
*http2ec = error_code;
|
||||
|
||||
SigMatch *sm = SigMatchAlloc();
|
||||
if (sm == NULL) {
|
||||
DetectHTTP2errorcodeFree(NULL, http2ec);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sm->type = DETECT_HTTP2_ERRORCODE;
|
||||
sm->ctx = (SigMatchCtx *)http2ec;
|
||||
|
||||
SigMatchAppendSMToList(s, sm, g_http2_match_buffer_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief this function will free memory associated with uint32_t
|
||||
*
|
||||
* \param ptr pointer to uint32_t
|
||||
*/
|
||||
void DetectHTTP2errorcodeFree(DetectEngineCtx *de_ctx, void *ptr)
|
||||
{
|
||||
SCFree(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief This function is used to match HTTP2 error code rule option on a transaction with those passed via http2.priority:
|
||||
*
|
||||
* \retval 0 no match
|
||||
* \retval 1 match
|
||||
*/
|
||||
static int DetectHTTP2priorityMatch(DetectEngineThreadCtx *det_ctx,
|
||||
Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
|
||||
const SigMatchCtx *ctx)
|
||||
|
||||
{
|
||||
uint32_t nb = 0;
|
||||
int value = rs_http2_tx_get_next_priority(txv, flags, nb);
|
||||
const DetectU8Data *du8 = (const DetectU8Data *)ctx;
|
||||
while (value >= 0) {
|
||||
if (DetectU8Match(value, du8)) {
|
||||
return 1;
|
||||
}
|
||||
nb++;
|
||||
value = rs_http2_tx_get_next_priority(txv, flags, nb);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief this function is used to attach the parsed http2.priority data into the current signature
|
||||
*
|
||||
* \param de_ctx pointer to the Detection Engine Context
|
||||
* \param s pointer to the Current Signature
|
||||
* \param str pointer to the user provided http2.priority options
|
||||
*
|
||||
* \retval 0 on Success
|
||||
* \retval -1 on Failure
|
||||
*/
|
||||
static int DetectHTTP2prioritySetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
|
||||
{
|
||||
if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
|
||||
return -1;
|
||||
|
||||
DetectU8Data *prio = DetectU8Parse(str);
|
||||
if (prio == NULL)
|
||||
return -1;
|
||||
|
||||
SigMatch *sm = SigMatchAlloc();
|
||||
if (sm == NULL) {
|
||||
SCFree(prio);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sm->type = DETECT_HTTP2_PRIORITY;
|
||||
sm->ctx = (SigMatchCtx *)prio;
|
||||
|
||||
SigMatchAppendSMToList(s, sm, g_http2_match_buffer_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief this function will free memory associated with uint32_t
|
||||
*
|
||||
* \param ptr pointer to DetectU8Data
|
||||
*/
|
||||
void DetectHTTP2priorityFree(DetectEngineCtx *de_ctx, void *ptr)
|
||||
{
|
||||
SCFree(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief This function is used to match HTTP2 window rule option on a transaction with those passed via http2.window:
|
||||
*
|
||||
* \retval 0 no match
|
||||
* \retval 1 match
|
||||
*/
|
||||
static int DetectHTTP2windowMatch(DetectEngineThreadCtx *det_ctx,
|
||||
Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
|
||||
const SigMatchCtx *ctx)
|
||||
|
||||
{
|
||||
uint32_t nb = 0;
|
||||
int value = rs_http2_tx_get_next_window(txv, flags, nb);
|
||||
const DetectU32Data *du32 = (const DetectU32Data *)ctx;
|
||||
while (value >= 0) {
|
||||
if (DetectU32Match(value, du32)) {
|
||||
return 1;
|
||||
}
|
||||
nb++;
|
||||
value = rs_http2_tx_get_next_window(txv, flags, nb);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief this function is used to attach the parsed http2.window data into the current signature
|
||||
*
|
||||
* \param de_ctx pointer to the Detection Engine Context
|
||||
* \param s pointer to the Current Signature
|
||||
* \param str pointer to the user provided http2.window options
|
||||
*
|
||||
* \retval 0 on Success
|
||||
* \retval -1 on Failure
|
||||
*/
|
||||
static int DetectHTTP2windowSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
|
||||
{
|
||||
if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
|
||||
return -1;
|
||||
|
||||
DetectU32Data *wu = DetectU32Parse(str);
|
||||
if (wu == NULL)
|
||||
return -1;
|
||||
|
||||
SigMatch *sm = SigMatchAlloc();
|
||||
if (sm == NULL) {
|
||||
SCFree(wu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sm->type = DETECT_HTTP2_WINDOW;
|
||||
sm->ctx = (SigMatchCtx *)wu;
|
||||
|
||||
SigMatchAppendSMToList(s, sm, g_http2_match_buffer_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief this function will free memory associated with uint32_t
|
||||
*
|
||||
* \param ptr pointer to DetectU8Data
|
||||
*/
|
||||
void DetectHTTP2windowFree(DetectEngineCtx *de_ctx, void *ptr)
|
||||
{
|
||||
SCFree(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief This function is used to match HTTP2 size update rule option on a transaction with those passed via http2.size_update:
|
||||
*
|
||||
* \retval 0 no match
|
||||
* \retval 1 match
|
||||
*/
|
||||
static int DetectHTTP2sizeUpdateMatch(DetectEngineThreadCtx *det_ctx,
|
||||
Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
|
||||
const SigMatchCtx *ctx)
|
||||
|
||||
{
|
||||
return rs_http2_detect_sizeupdatectx_match(ctx, txv, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief this function is used to attach the parsed http2.size_update data into the current signature
|
||||
*
|
||||
* \param de_ctx pointer to the Detection Engine Context
|
||||
* \param s pointer to the Current Signature
|
||||
* \param str pointer to the user provided http2.size_update options
|
||||
*
|
||||
* \retval 0 on Success
|
||||
* \retval -1 on Failure
|
||||
*/
|
||||
static int DetectHTTP2sizeUpdateSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
|
||||
{
|
||||
if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
|
||||
return -1;
|
||||
|
||||
void *su = rs_detect_u64_parse(str);
|
||||
if (su == NULL)
|
||||
return -1;
|
||||
|
||||
SigMatch *sm = SigMatchAlloc();
|
||||
if (sm == NULL) {
|
||||
DetectHTTP2settingsFree(NULL, su);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sm->type = DETECT_HTTP2_SIZEUPDATE;
|
||||
sm->ctx = (SigMatchCtx *)su;
|
||||
|
||||
SigMatchAppendSMToList(s, sm, g_http2_match_buffer_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief this function will free memory associated with uint32_t
|
||||
*
|
||||
* \param ptr pointer to DetectU8Data
|
||||
*/
|
||||
void DetectHTTP2sizeUpdateFree(DetectEngineCtx *de_ctx, void *ptr)
|
||||
{
|
||||
rs_detect_u64_free(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief This function is used to match HTTP2 error code rule option on a transaction with those passed via http2.settings:
|
||||
*
|
||||
* \retval 0 no match
|
||||
* \retval 1 match
|
||||
*/
|
||||
static int DetectHTTP2settingsMatch(DetectEngineThreadCtx *det_ctx,
|
||||
Flow *f, uint8_t flags, void *state, void *txv, const Signature *s,
|
||||
const SigMatchCtx *ctx)
|
||||
|
||||
{
|
||||
return rs_http2_detect_settingsctx_match(ctx, txv, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief this function is used to attach the parsed http2.settings data into the current signature
|
||||
*
|
||||
* \param de_ctx pointer to the Detection Engine Context
|
||||
* \param s pointer to the Current Signature
|
||||
* \param str pointer to the user provided http2.settings options
|
||||
*
|
||||
* \retval 0 on Success
|
||||
* \retval -1 on Failure
|
||||
*/
|
||||
static int DetectHTTP2settingsSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
|
||||
{
|
||||
if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
|
||||
return -1;
|
||||
|
||||
void *http2set = rs_http2_detect_settingsctx_parse(str);
|
||||
if (http2set == NULL)
|
||||
return -1;
|
||||
|
||||
SigMatch *sm = SigMatchAlloc();
|
||||
if (sm == NULL) {
|
||||
DetectHTTP2settingsFree(NULL, http2set);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sm->type = DETECT_HTTP2_SETTINGS;
|
||||
sm->ctx = (SigMatchCtx *)http2set;
|
||||
|
||||
SigMatchAppendSMToList(s, sm, g_http2_match_buffer_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief this function will free memory associated with rust signature context
|
||||
*
|
||||
* \param ptr pointer to rust signature context
|
||||
*/
|
||||
void DetectHTTP2settingsFree(DetectEngineCtx *de_ctx, void *ptr)
|
||||
{
|
||||
rs_http2_detect_settingsctx_free(ptr);
|
||||
}
|
||||
|
||||
static int DetectHTTP2headerNameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
|
||||
{
|
||||
if (DetectBufferSetActiveList(s, g_http2_header_name_buffer_id) < 0)
|
||||
return -1;
|
||||
|
||||
if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void PrefilterMpmHttp2HNameFree(void *ptr)
|
||||
{
|
||||
SCFree(ptr);
|
||||
}
|
||||
|
||||
static InspectionBuffer *GetHttp2HNameData(DetectEngineThreadCtx *det_ctx,
|
||||
const uint8_t flags, const DetectEngineTransforms *transforms,
|
||||
Flow *_f, const struct MpmListIdDataArgs *cbdata,
|
||||
int list_id, bool first)
|
||||
{
|
||||
SCEnter();
|
||||
|
||||
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id);
|
||||
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, cbdata->local_id);
|
||||
if (buffer == NULL)
|
||||
return NULL;
|
||||
if (!first && buffer->inspect != NULL)
|
||||
return buffer;
|
||||
|
||||
uint32_t b_len = 0;
|
||||
const uint8_t *b = NULL;
|
||||
|
||||
if (rs_http2_tx_get_header_name(cbdata->txv, flags, (uint32_t)cbdata->local_id, &b, &b_len) != 1)
|
||||
return NULL;
|
||||
if (b == NULL || b_len == 0)
|
||||
return NULL;
|
||||
|
||||
InspectionBufferSetup(buffer, b, b_len);
|
||||
InspectionBufferApplyTransforms(buffer, transforms);
|
||||
|
||||
SCReturnPtr(buffer, "InspectionBuffer");
|
||||
}
|
||||
|
||||
static void PrefilterTxHttp2HName(DetectEngineThreadCtx *det_ctx,
|
||||
const void *pectx,
|
||||
Packet *p, Flow *f, void *txv,
|
||||
const uint64_t idx, const uint8_t flags)
|
||||
{
|
||||
SCEnter();
|
||||
|
||||
const PrefilterMpmListId *ctx = (const PrefilterMpmListId *)pectx;
|
||||
const MpmCtx *mpm_ctx = ctx->mpm_ctx;
|
||||
const int list_id = ctx->list_id;
|
||||
|
||||
int local_id = 0;
|
||||
|
||||
while(1) {
|
||||
// loop until we get a NULL
|
||||
|
||||
struct MpmListIdDataArgs cbdata = { local_id, txv };
|
||||
InspectionBuffer *buffer = GetHttp2HNameData(det_ctx, flags, ctx->transforms,
|
||||
f, &cbdata, list_id, true);
|
||||
if (buffer == NULL)
|
||||
break;
|
||||
|
||||
if (buffer->inspect_len >= mpm_ctx->minlen) {
|
||||
(void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx,
|
||||
&det_ctx->mtcu, &det_ctx->pmq,
|
||||
buffer->inspect, buffer->inspect_len);
|
||||
}
|
||||
|
||||
local_id++;
|
||||
}
|
||||
}
|
||||
|
||||
static int PrefilterMpmHttp2HeaderNameRegister(DetectEngineCtx *de_ctx,
|
||||
SigGroupHead *sgh, MpmCtx *mpm_ctx,
|
||||
const DetectBufferMpmRegistery *mpm_reg, int list_id)
|
||||
{
|
||||
//TODOask use PrefilterMpmListId elsewhere
|
||||
PrefilterMpmListId *pectx = SCCalloc(1, sizeof(*pectx));
|
||||
if (pectx == NULL)
|
||||
return -1;
|
||||
pectx->list_id = list_id;
|
||||
pectx->mpm_ctx = mpm_ctx;
|
||||
pectx->transforms = &mpm_reg->transforms;
|
||||
|
||||
return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxHttp2HName,
|
||||
mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress,
|
||||
pectx, PrefilterMpmHttp2HNameFree, mpm_reg->name);
|
||||
}
|
||||
|
||||
static int DetectEngineInspectHttp2HeaderName(
|
||||
DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
|
||||
const DetectEngineAppInspectionEngine *engine,
|
||||
const Signature *s,
|
||||
Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
|
||||
{
|
||||
int local_id = 0;
|
||||
|
||||
const DetectEngineTransforms *transforms = NULL;
|
||||
if (!engine->mpm) {
|
||||
transforms = engine->v2.transforms;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
//TODOask use MpmListIdDataArgs elsewhere
|
||||
struct MpmListIdDataArgs cbdata = { local_id, txv, };
|
||||
InspectionBuffer *buffer = GetHttp2HNameData(det_ctx, flags,
|
||||
transforms, f, &cbdata, engine->sm_list, false);
|
||||
|
||||
if (buffer == NULL || buffer->inspect == NULL)
|
||||
break;
|
||||
|
||||
det_ctx->buffer_offset = 0;
|
||||
det_ctx->discontinue_matching = 0;
|
||||
det_ctx->inspection_recursion_counter = 0;
|
||||
|
||||
const int match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd,
|
||||
NULL, f,
|
||||
(uint8_t *)buffer->inspect,
|
||||
buffer->inspect_len,
|
||||
buffer->inspect_offset, DETECT_CI_FLAGS_SINGLE,
|
||||
DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE);
|
||||
if (match == 1) {
|
||||
return DETECT_ENGINE_INSPECT_SIG_MATCH;
|
||||
}
|
||||
local_id++;
|
||||
}
|
||||
|
||||
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
|
||||
}
|
||||
|
||||
static int DetectHTTP2headerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
|
||||
{
|
||||
if (DetectBufferSetActiveList(s, g_http2_header_buffer_id) < 0)
|
||||
return -1;
|
||||
|
||||
if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void PrefilterMpmHttp2HeaderFree(void *ptr)
|
||||
{
|
||||
SCFree(ptr);
|
||||
}
|
||||
|
||||
static InspectionBuffer *GetHttp2HeaderData(DetectEngineThreadCtx *det_ctx,
|
||||
const uint8_t flags, const DetectEngineTransforms *transforms,
|
||||
Flow *_f, const struct MpmListIdDataArgs *cbdata,
|
||||
int list_id, bool first)
|
||||
{
|
||||
SCEnter();
|
||||
|
||||
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id);
|
||||
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, cbdata->local_id);
|
||||
if (buffer == NULL)
|
||||
return NULL;
|
||||
if (!first && buffer->inspect != NULL)
|
||||
return buffer;
|
||||
|
||||
uint32_t b_len = 0;
|
||||
const uint8_t *b = NULL;
|
||||
|
||||
if (rs_http2_tx_get_header(cbdata->txv, flags, (uint32_t)cbdata->local_id, &b, &b_len) != 1)
|
||||
return NULL;
|
||||
if (b == NULL || b_len == 0)
|
||||
return NULL;
|
||||
|
||||
InspectionBufferSetup(buffer, b, b_len);
|
||||
InspectionBufferApplyTransforms(buffer, transforms);
|
||||
|
||||
SCReturnPtr(buffer, "InspectionBuffer");
|
||||
}
|
||||
|
||||
static void PrefilterTxHttp2Header(DetectEngineThreadCtx *det_ctx,
|
||||
const void *pectx,
|
||||
Packet *p, Flow *f, void *txv,
|
||||
const uint64_t idx, const uint8_t flags)
|
||||
{
|
||||
SCEnter();
|
||||
|
||||
const PrefilterMpmListId *ctx = (const PrefilterMpmListId *)pectx;
|
||||
const MpmCtx *mpm_ctx = ctx->mpm_ctx;
|
||||
const int list_id = ctx->list_id;
|
||||
|
||||
int local_id = 0;
|
||||
|
||||
while(1) {
|
||||
// loop until we get a NULL
|
||||
|
||||
struct MpmListIdDataArgs cbdata = { local_id, txv };
|
||||
InspectionBuffer *buffer = GetHttp2HeaderData(det_ctx, flags, ctx->transforms,
|
||||
f, &cbdata, list_id, true);
|
||||
if (buffer == NULL)
|
||||
break;
|
||||
|
||||
if (buffer->inspect_len >= mpm_ctx->minlen) {
|
||||
(void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx,
|
||||
&det_ctx->mtcu, &det_ctx->pmq,
|
||||
buffer->inspect, buffer->inspect_len);
|
||||
}
|
||||
|
||||
local_id++;
|
||||
}
|
||||
}
|
||||
|
||||
static int PrefilterMpmHttp2HeaderRegister(DetectEngineCtx *de_ctx,
|
||||
SigGroupHead *sgh, MpmCtx *mpm_ctx,
|
||||
const DetectBufferMpmRegistery *mpm_reg, int list_id)
|
||||
{
|
||||
PrefilterMpmListId *pectx = SCCalloc(1, sizeof(*pectx));
|
||||
if (pectx == NULL)
|
||||
return -1;
|
||||
pectx->list_id = list_id;
|
||||
pectx->mpm_ctx = mpm_ctx;
|
||||
pectx->transforms = &mpm_reg->transforms;
|
||||
|
||||
return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTxHttp2Header,
|
||||
mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress,
|
||||
pectx, PrefilterMpmHttp2HeaderFree, mpm_reg->name);
|
||||
}
|
||||
|
||||
static int DetectEngineInspectHttp2Header(
|
||||
DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
|
||||
const DetectEngineAppInspectionEngine *engine,
|
||||
const Signature *s,
|
||||
Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
|
||||
{
|
||||
int local_id = 0;
|
||||
|
||||
const DetectEngineTransforms *transforms = NULL;
|
||||
if (!engine->mpm) {
|
||||
transforms = engine->v2.transforms;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
struct MpmListIdDataArgs cbdata = { local_id, txv, };
|
||||
InspectionBuffer *buffer = GetHttp2HeaderData(det_ctx, flags,
|
||||
transforms, f, &cbdata, engine->sm_list, false);
|
||||
|
||||
if (buffer == NULL || buffer->inspect == NULL)
|
||||
break;
|
||||
|
||||
det_ctx->buffer_offset = 0;
|
||||
det_ctx->discontinue_matching = 0;
|
||||
det_ctx->inspection_recursion_counter = 0;
|
||||
|
||||
const int match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd,
|
||||
NULL, f,
|
||||
(uint8_t *)buffer->inspect,
|
||||
buffer->inspect_len,
|
||||
buffer->inspect_offset, DETECT_CI_FLAGS_SINGLE,
|
||||
DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE);
|
||||
if (match == 1) {
|
||||
return DETECT_ENGINE_INSPECT_SIG_MATCH;
|
||||
}
|
||||
local_id++;
|
||||
}
|
||||
|
||||
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
|
||||
}
|
||||
|
||||
static bool DetectHttp2HeaderValidateCallback(const Signature *s, const char **sigerror)
|
||||
{
|
||||
const SigMatch *sm = s->init_data->smlists[g_http2_header_buffer_id];
|
||||
for ( ; sm != NULL; sm = sm->next) {
|
||||
if (sm->type != DETECT_CONTENT)
|
||||
continue;
|
||||
const DetectContentData *cd = (DetectContentData *)sm->ctx;
|
||||
bool escaped = false;
|
||||
bool namevaluesep = false;
|
||||
for (size_t i = 0; i < cd->content_len; ++i) {
|
||||
if (escaped) {
|
||||
if (cd->content[i] == ' ') {
|
||||
if (namevaluesep) {
|
||||
*sigerror = "Invalid http2.header string : "
|
||||
"': ' is a special sequence for separation between name and value "
|
||||
" and thus can only be present once";
|
||||
SCLogWarning(SC_WARN_POOR_RULE, "rule %u: %s", s->id, *sigerror);
|
||||
return false;
|
||||
}
|
||||
namevaluesep = true;
|
||||
} else if (cd->content[i] != ':') {
|
||||
*sigerror = "Invalid http2.header string : "
|
||||
"':' is an escaping character for itself, "
|
||||
"or space for the separation between name and value";
|
||||
SCLogWarning(SC_WARN_POOR_RULE, "rule %u: %s", s->id, *sigerror);
|
||||
return false;
|
||||
}
|
||||
escaped = false;
|
||||
} else if(cd->content[i] == ':') {
|
||||
escaped = true;
|
||||
}
|
||||
}
|
||||
if (escaped) {
|
||||
*sigerror = "Invalid http2.header string : "
|
||||
"':' is an escaping character for itself, "
|
||||
"or space for the separation between name and value";
|
||||
SCLogWarning(SC_WARN_POOR_RULE, "rule %u: %s", s->id, *sigerror);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef UNITTESTS
|
||||
#include "tests/detect-http2.c"
|
||||
#endif
|
||||
@ -0,0 +1,29 @@
|
||||
/* Copyright (C) 2020 Open Information Security Foundation
|
||||
*
|
||||
* You can copy, redistribute or modify this Program under the terms of
|
||||
* the GNU General Public License version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Philippe Antoine <p.antoine@catenacyber.fr>
|
||||
*/
|
||||
|
||||
#ifndef _DETECT_HTTP2_H
|
||||
#define _DETECT_HTTP2_H
|
||||
|
||||
void DetectHttp2Register(void);
|
||||
|
||||
#endif /* _DETECT_HTTP2_H */
|
||||
@ -0,0 +1,251 @@
|
||||
/* Copyright (C) 2020 Open Information Security Foundation
|
||||
*
|
||||
* You can copy, redistribute or modify this Program under the terms of
|
||||
* the GNU General Public License version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Philippe Antoine <p.antoine@catenacyber.fr>
|
||||
*
|
||||
* Implements HTTP2 JSON logging portion of the engine.
|
||||
*/
|
||||
|
||||
#include "suricata-common.h"
|
||||
#include "debug.h"
|
||||
#include "detect.h"
|
||||
#include "pkt-var.h"
|
||||
#include "conf.h"
|
||||
|
||||
#include "threads.h"
|
||||
#include "threadvars.h"
|
||||
#include "tm-threads.h"
|
||||
|
||||
#include "util-print.h"
|
||||
#include "util-unittest.h"
|
||||
|
||||
#include "util-debug.h"
|
||||
#include "app-layer-parser.h"
|
||||
#include "output.h"
|
||||
#include "app-layer-http2.h"
|
||||
#include "app-layer.h"
|
||||
#include "util-privs.h"
|
||||
#include "util-buffer.h"
|
||||
|
||||
#include "util-logopenfile.h"
|
||||
#include "util-crypt.h"
|
||||
|
||||
#include "output-json.h"
|
||||
#include "output-json-http2.h"
|
||||
#include "rust.h"
|
||||
|
||||
#define MODULE_NAME "LogHttp2Log"
|
||||
|
||||
typedef struct OutputHttp2Ctx_ {
|
||||
LogFileCtx *file_ctx;
|
||||
OutputJsonCommonSettings cfg;
|
||||
} OutputHttp2Ctx;
|
||||
|
||||
|
||||
typedef struct JsonHttp2LogThread_ {
|
||||
OutputHttp2Ctx *http2log_ctx;
|
||||
MemBuffer *buffer;
|
||||
} JsonHttp2LogThread;
|
||||
|
||||
|
||||
bool EveHTTP2AddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *jb)
|
||||
{
|
||||
void *state = FlowGetAppState(f);
|
||||
if (state) {
|
||||
void *tx = AppLayerParserGetTx(f->proto, ALPROTO_HTTP2, state, tx_id);
|
||||
if (tx) {
|
||||
return rs_http2_log_json(tx, jb);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int JsonHttp2Logger(ThreadVars *tv, void *thread_data, const Packet *p,
|
||||
Flow *f, void *state, void *txptr, uint64_t tx_id)
|
||||
{
|
||||
JsonHttp2LogThread *aft = (JsonHttp2LogThread *)thread_data;
|
||||
OutputHttp2Ctx *http2_ctx = aft->http2log_ctx;
|
||||
|
||||
if (unlikely(state == NULL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
JsonBuilder *js = CreateEveHeaderWithTxId(p, LOG_DIR_FLOW, "http2", NULL, tx_id);
|
||||
if (unlikely(js == NULL))
|
||||
return 0;
|
||||
|
||||
EveAddCommonOptions(&http2_ctx->cfg, p, f, js);
|
||||
|
||||
/* reset */
|
||||
MemBufferReset(aft->buffer);
|
||||
|
||||
jb_open_object(js, "http2");
|
||||
if (!rs_http2_log_json(txptr, js)) {
|
||||
goto end;
|
||||
}
|
||||
jb_close(js);
|
||||
OutputJsonBuilderBuffer(js, http2_ctx->file_ctx, &aft->buffer);
|
||||
end:
|
||||
jb_free(js);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TmEcode JsonHttp2LogThreadInit(ThreadVars *t, const void *initdata, void **data)
|
||||
{
|
||||
JsonHttp2LogThread *aft = SCMalloc(sizeof(JsonHttp2LogThread));
|
||||
if (unlikely(aft == NULL))
|
||||
return TM_ECODE_FAILED;
|
||||
memset(aft, 0, sizeof(JsonHttp2LogThread));
|
||||
|
||||
if(initdata == NULL)
|
||||
{
|
||||
SCLogDebug("Error getting context for EveLogHTTP2. \"initdata\" argument NULL");
|
||||
SCFree(aft);
|
||||
return TM_ECODE_FAILED;
|
||||
}
|
||||
|
||||
/* Use the Ouptut Context (file pointer and mutex) */
|
||||
aft->http2log_ctx = ((OutputCtx *)initdata)->data;
|
||||
|
||||
aft->buffer = MemBufferCreateNew(JSON_OUTPUT_BUFFER_SIZE);
|
||||
if (aft->buffer == NULL) {
|
||||
SCFree(aft);
|
||||
return TM_ECODE_FAILED;
|
||||
}
|
||||
|
||||
*data = (void *)aft;
|
||||
return TM_ECODE_OK;
|
||||
}
|
||||
|
||||
static TmEcode JsonHttp2LogThreadDeinit(ThreadVars *t, void *data)
|
||||
{
|
||||
JsonHttp2LogThread *aft = (JsonHttp2LogThread *)data;
|
||||
if (aft == NULL) {
|
||||
return TM_ECODE_OK;
|
||||
}
|
||||
|
||||
MemBufferFree(aft->buffer);
|
||||
/* clear memory */
|
||||
memset(aft, 0, sizeof(JsonHttp2LogThread));
|
||||
|
||||
SCFree(aft);
|
||||
return TM_ECODE_OK;
|
||||
}
|
||||
|
||||
static void OutputHttp2LogDeinit(OutputCtx *output_ctx)
|
||||
{
|
||||
OutputHttp2Ctx *http2_ctx = output_ctx->data;
|
||||
LogFileCtx *logfile_ctx = http2_ctx->file_ctx;
|
||||
LogFileFreeCtx(logfile_ctx);
|
||||
SCFree(http2_ctx);
|
||||
SCFree(output_ctx);
|
||||
}
|
||||
|
||||
#define DEFAULT_LOG_FILENAME "http2.json"
|
||||
static OutputInitResult OutputHttp2LogInit(ConfNode *conf)
|
||||
{
|
||||
OutputInitResult result = { NULL, false };
|
||||
LogFileCtx *file_ctx = LogFileNewCtx();
|
||||
if(file_ctx == NULL) {
|
||||
SCLogError(SC_ERR_HTTP2_LOG_GENERIC, "couldn't create new file_ctx");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) {
|
||||
LogFileFreeCtx(file_ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
OutputHttp2Ctx *http2_ctx = SCMalloc(sizeof(OutputHttp2Ctx));
|
||||
if (unlikely(http2_ctx == NULL)) {
|
||||
LogFileFreeCtx(file_ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
|
||||
if (unlikely(output_ctx == NULL)) {
|
||||
LogFileFreeCtx(file_ctx);
|
||||
SCFree(http2_ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
http2_ctx->file_ctx = file_ctx;
|
||||
|
||||
output_ctx->data = http2_ctx;
|
||||
output_ctx->DeInit = OutputHttp2LogDeinit;
|
||||
|
||||
AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP2);
|
||||
|
||||
result.ctx = output_ctx;
|
||||
result.ok = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void OutputHttp2LogDeinitSub(OutputCtx *output_ctx)
|
||||
{
|
||||
OutputHttp2Ctx *http2_ctx = output_ctx->data;
|
||||
SCFree(http2_ctx);
|
||||
SCFree(output_ctx);
|
||||
}
|
||||
|
||||
static OutputInitResult OutputHttp2LogInitSub(ConfNode *conf, OutputCtx *parent_ctx)
|
||||
{
|
||||
OutputInitResult result = { NULL, false };
|
||||
OutputJsonCtx *ojc = parent_ctx->data;
|
||||
|
||||
OutputHttp2Ctx *http2_ctx = SCMalloc(sizeof(OutputHttp2Ctx));
|
||||
if (unlikely(http2_ctx == NULL))
|
||||
return result;
|
||||
|
||||
OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
|
||||
if (unlikely(output_ctx == NULL)) {
|
||||
SCFree(http2_ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
http2_ctx->file_ctx = ojc->file_ctx;
|
||||
http2_ctx->cfg = ojc->cfg;
|
||||
|
||||
output_ctx->data = http2_ctx;
|
||||
output_ctx->DeInit = OutputHttp2LogDeinitSub;
|
||||
|
||||
AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP2);
|
||||
|
||||
result.ctx = output_ctx;
|
||||
result.ok = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
void JsonHttp2LogRegister (void)
|
||||
{
|
||||
/* register as separate module */
|
||||
OutputRegisterTxModuleWithProgress(LOGGER_JSON_HTTP2,
|
||||
MODULE_NAME, "http2-json-log",
|
||||
OutputHttp2LogInit, ALPROTO_HTTP2, JsonHttp2Logger,
|
||||
HTTP2StateClosed, HTTP2StateClosed,
|
||||
JsonHttp2LogThreadInit, JsonHttp2LogThreadDeinit, NULL);
|
||||
|
||||
/* also register as child of eve-log */
|
||||
OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_HTTP2,
|
||||
"eve-log", MODULE_NAME, "eve-log.http2",
|
||||
OutputHttp2LogInitSub, ALPROTO_HTTP2, JsonHttp2Logger,
|
||||
HTTP2StateClosed, HTTP2StateClosed,
|
||||
JsonHttp2LogThreadInit, JsonHttp2LogThreadDeinit, NULL);
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
/* Copyright (C) 2020 Open Information Security Foundation
|
||||
*
|
||||
* You can copy, redistribute or modify this Program under the terms of
|
||||
* the GNU General Public License version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \author Philippe Antoine <p.antoine@catenacyber.fr>
|
||||
*/
|
||||
|
||||
#ifndef __OUTPUT_JSON_HTTP2_H__
|
||||
#define __OUTPUT_JSON_HTTP2_H__
|
||||
|
||||
void JsonHttp2LogRegister(void);
|
||||
bool EveHTTP2AddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *jb);
|
||||
|
||||
#endif /* __OUTPUT_JSON_HTTP2_H__ */
|
||||
@ -0,0 +1,161 @@
|
||||
/* Copyright (C) 2020 Open Information Security Foundation
|
||||
*
|
||||
* You can copy, redistribute or modify this Program under the terms of
|
||||
* the GNU General Public License version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "../suricata-common.h"
|
||||
|
||||
#include "../detect-engine.h"
|
||||
|
||||
#include "../detect-http2.h"
|
||||
|
||||
#include "../util-unittest.h"
|
||||
|
||||
/**
|
||||
* \test signature with a valid http2.frametype value.
|
||||
*/
|
||||
|
||||
static int DetectHTTP2frameTypeParseTest01 (void)
|
||||
{
|
||||
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
||||
FAIL_IF_NULL(de_ctx);
|
||||
|
||||
Signature *sig = DetectEngineAppendSig(de_ctx,
|
||||
"alert http2 any any -> any any (http2.frametype:GOAWAY; sid:1; rev:1;)");
|
||||
FAIL_IF_NULL(sig);
|
||||
|
||||
DetectEngineCtxFree(de_ctx);
|
||||
PASS;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief this function registers unit tests for DetectHTTP2frameType
|
||||
*/
|
||||
void DetectHTTP2frameTypeRegisterTests(void)
|
||||
{
|
||||
UtRegisterTest("DetectHTTP2frameTypeParseTest01", DetectHTTP2frameTypeParseTest01);
|
||||
}
|
||||
|
||||
/**
|
||||
* \test signature with a valid http2.errorcode value.
|
||||
*/
|
||||
|
||||
static int DetectHTTP2errorCodeParseTest01 (void)
|
||||
{
|
||||
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
||||
FAIL_IF_NULL(de_ctx);
|
||||
|
||||
Signature *sig = DetectEngineAppendSig(de_ctx,
|
||||
"alert http2 any any -> any any (http2.errorcode:NO_ERROR; sid:1; rev:1;)");
|
||||
FAIL_IF_NULL(sig);
|
||||
|
||||
DetectEngineCtxFree(de_ctx);
|
||||
PASS;
|
||||
}
|
||||
|
||||
void DetectHTTP2errorCodeRegisterTests(void)
|
||||
{
|
||||
UtRegisterTest("DetectHTTP2errorCodeParseTest01", DetectHTTP2errorCodeParseTest01);
|
||||
}
|
||||
|
||||
/**
|
||||
* \test signature with a valid http2.priority value.
|
||||
*/
|
||||
|
||||
static int DetectHTTP2priorityParseTest01 (void)
|
||||
{
|
||||
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
||||
FAIL_IF_NULL(de_ctx);
|
||||
|
||||
Signature *sig = DetectEngineAppendSig(de_ctx,
|
||||
"alert http2 any any -> any any (http2.priority:>100; sid:1; rev:1;)");
|
||||
FAIL_IF_NULL(sig);
|
||||
|
||||
DetectEngineCtxFree(de_ctx);
|
||||
PASS;
|
||||
}
|
||||
|
||||
void DetectHTTP2priorityRegisterTests(void)
|
||||
{
|
||||
UtRegisterTest("DetectHTTP2priorityParseTest01", DetectHTTP2priorityParseTest01);
|
||||
}
|
||||
|
||||
/**
|
||||
* \test signature with a valid http2.window value.
|
||||
*/
|
||||
|
||||
static int DetectHTTP2windowParseTest01 (void)
|
||||
{
|
||||
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
||||
FAIL_IF_NULL(de_ctx);
|
||||
|
||||
Signature *sig = DetectEngineAppendSig(de_ctx,
|
||||
"alert http2 any any -> any any (http2.window:<42; sid:1; rev:1;)");
|
||||
FAIL_IF_NULL(sig);
|
||||
|
||||
DetectEngineCtxFree(de_ctx);
|
||||
PASS;
|
||||
}
|
||||
|
||||
void DetectHTTP2windowRegisterTests(void)
|
||||
{
|
||||
UtRegisterTest("DetectHTTP2windowParseTest01", DetectHTTP2windowParseTest01);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \test signature with a valid http2.settings value.
|
||||
*/
|
||||
|
||||
static int DetectHTTP2settingsParseTest01 (void)
|
||||
{
|
||||
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
||||
FAIL_IF_NULL(de_ctx);
|
||||
|
||||
Signature *sig = DetectEngineAppendSig(de_ctx,
|
||||
"alert http2 any any -> any any (http2.settings:SETTINGS_MAX_HEADER_LIST_SIZE >1024; sid:1; rev:1;)");
|
||||
FAIL_IF_NULL(sig);
|
||||
|
||||
DetectEngineCtxFree(de_ctx);
|
||||
PASS;
|
||||
}
|
||||
|
||||
void DetectHTTP2settingsRegisterTests(void)
|
||||
{
|
||||
UtRegisterTest("DetectHTTP2settingsParseTest01", DetectHTTP2settingsParseTest01);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \test signature with a valid http2.size_update value.
|
||||
*/
|
||||
|
||||
static int DetectHTTP2sizeUpdateParseTest01 (void)
|
||||
{
|
||||
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
||||
FAIL_IF_NULL(de_ctx);
|
||||
|
||||
Signature *sig = DetectEngineAppendSig(de_ctx,
|
||||
"alert http2 any any -> any any (http2.size_update:>4096; sid:1; rev:1;)");
|
||||
FAIL_IF_NULL(sig);
|
||||
|
||||
DetectEngineCtxFree(de_ctx);
|
||||
PASS;
|
||||
}
|
||||
|
||||
void DetectHTTP2sizeUpdateRegisterTests(void)
|
||||
{
|
||||
UtRegisterTest("DetectHTTP2sizeUpdateParseTest01", DetectHTTP2sizeUpdateParseTest01);
|
||||
}
|
||||
Loading…
Reference in New Issue