detect: http2.frametype is now a generic integer

Ticket: 7889
pull/14025/head
Philippe Antoine 1 year ago committed by Victor Julien
parent 454f73b445
commit 401b2fcae6

@ -20,6 +20,12 @@ http2.frametype
Match on the frame type present in a transaction. Match on the frame type present in a transaction.
http2.frametype uses an :ref:`unsigned 8-bit integer <rules-integer-keywords>`.
http2.frametype is also a :ref:`multi-integer <multi-integers>`.
http2.frametype does not have any corresponding log output.
Examples:: Examples::
http2.frametype:GOAWAY; http2.frametype:GOAWAY;
@ -67,6 +73,8 @@ http2.window uses an :ref:`unsigned 32-bit integer <rules-integer-keywords>`.
http2.window is also a :ref:`multi-integer <multi-integers>`. http2.window is also a :ref:`multi-integer <multi-integers>`.
http2.window does not have any corresponding log output.
This keyword takes a numeric argument after a colon and supports additional qualifiers, such as: This keyword takes a numeric argument after a colon and supports additional qualifiers, such as:
* ``>`` (greater than) * ``>`` (greater than)

@ -20,7 +20,8 @@ use super::http2::{
}; };
use super::parser; use super::parser;
use crate::detect::uint::{ use crate::detect::uint::{
detect_match_uint, detect_uint_match_at_index, DetectUintArrayData, DetectUintData, detect_match_uint, detect_parse_array_uint_enum, detect_uint_match_at_index,
DetectUintArrayData, DetectUintData,
}; };
use crate::direction::Direction; use crate::direction::Direction;
use base64::{engine::general_purpose::STANDARD, Engine}; use base64::{engine::general_purpose::STANDARD, Engine};
@ -30,44 +31,38 @@ use std::rc::Rc;
use std::str::FromStr; use std::str::FromStr;
use suricata_sys::sys::DetectEngineThreadCtx; use suricata_sys::sys::DetectEngineThreadCtx;
fn http2_tx_has_frametype(
tx: &HTTP2Transaction, direction: Direction, value: u8,
) -> std::os::raw::c_int {
if direction == Direction::ToServer {
for i in 0..tx.frames_ts.len() {
if tx.frames_ts[i].header.ftype == value {
return 1;
}
}
} else {
for i in 0..tx.frames_tc.len() {
if tx.frames_tc[i].header.ftype == value {
return 1;
}
}
}
return 0;
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn SCHttp2TxHasFrametype( pub unsafe extern "C" fn SCHttp2TxHasFrametype(
tx: *mut std::os::raw::c_void, direction: u8, value: u8, tx: *mut std::os::raw::c_void, direction: u8, ctx: *const std::os::raw::c_void,
) -> std::os::raw::c_int { ) -> std::os::raw::c_int {
let tx = cast_pointer!(tx, HTTP2Transaction); let tx = cast_pointer!(tx, HTTP2Transaction);
return http2_tx_has_frametype(tx, direction.into(), value); let ctx = cast_pointer!(ctx, DetectUintArrayData<u8>);
let frames = if direction & Direction::ToServer as u8 != 0 {
&tx.frames_ts
} else {
&tx.frames_tc
};
return detect_uint_match_at_index::<HTTP2Frame, u8>(
frames,
ctx,
|f| Some(f.header.ftype),
tx.state >= HTTP2TransactionState::HTTP2StateClosed,
);
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn SCHttp2ParseFrametype( pub unsafe extern "C" fn SCHttp2ParseFrametype(
str: *const std::os::raw::c_char, str: *const std::os::raw::c_char,
) -> std::os::raw::c_int { ) -> *mut std::os::raw::c_void {
let ft_name: &CStr = CStr::from_ptr(str); //unsafe let ft_name: &CStr = CStr::from_ptr(str); //unsafe
if let Ok(s) = ft_name.to_str() { if let Ok(s) = ft_name.to_str() {
if let Ok(x) = parser::HTTP2FrameType::from_str(s) { if let Some(ctx) = detect_parse_array_uint_enum::<u8, parser::HTTP2FrameType>(s) {
return x as i32; let boxed = Box::new(ctx);
// DetectUintArrayData<u8> cannot be cbindgend
return Box::into_raw(boxed) as *mut c_void;
} }
} }
return -1; return std::ptr::null_mut();
} }
fn http2_tx_has_errorcode( fn http2_tx_has_errorcode(

@ -35,7 +35,10 @@ use std::rc::Rc;
use base64::{Engine, engine::general_purpose::STANDARD_NO_PAD}; use base64::{Engine, engine::general_purpose::STANDARD_NO_PAD};
#[repr(u8)] #[repr(u8)]
#[derive(EnumStringU8)]
#[derive(Clone, Copy, PartialEq, Eq, FromPrimitive, Debug)] #[derive(Clone, Copy, PartialEq, Eq, FromPrimitive, Debug)]
// parse GOAWAY, not GO_AWAY
#[suricata(enum_string_style = "UPPERCASE")]
pub enum HTTP2FrameType { pub enum HTTP2FrameType {
Data = 0, Data = 0,
Headers = 1, Headers = 1,
@ -49,34 +52,6 @@ pub enum HTTP2FrameType {
Continuation = 9, Continuation = 9,
} }
impl fmt::Display for HTTP2FrameType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl std::str::FromStr for HTTP2FrameType {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let su = s.to_uppercase();
let su_slice: &str = &su;
match su_slice {
"DATA" => Ok(HTTP2FrameType::Data),
"HEADERS" => Ok(HTTP2FrameType::Headers),
"PRIORITY" => Ok(HTTP2FrameType::Priority),
"RSTSTREAM" => Ok(HTTP2FrameType::RstStream),
"SETTINGS" => Ok(HTTP2FrameType::Settings),
"PUSHPROMISE" => Ok(HTTP2FrameType::PushPromise),
"PING" => Ok(HTTP2FrameType::Ping),
"GOAWAY" => Ok(HTTP2FrameType::GoAway),
"WINDOWUPDATE" => Ok(HTTP2FrameType::WindowUpdate),
"CONTINUATION" => Ok(HTTP2FrameType::Continuation),
_ => Err(format!("'{}' is not a valid value for HTTP2FrameType", s)),
}
}
}
#[derive(PartialEq, Eq, Debug)] #[derive(PartialEq, Eq, Debug)]
pub struct HTTP2FrameHeader { pub struct HTTP2FrameHeader {
//we could add detection on (GOAWAY) additional data //we could add detection on (GOAWAY) additional data

@ -110,6 +110,8 @@ void DetectHttp2Register(void)
sigmatch_table[DETECT_HTTP2_FRAMETYPE].AppLayerTxMatch = DetectHTTP2frametypeMatch; sigmatch_table[DETECT_HTTP2_FRAMETYPE].AppLayerTxMatch = DetectHTTP2frametypeMatch;
sigmatch_table[DETECT_HTTP2_FRAMETYPE].Setup = DetectHTTP2frametypeSetup; sigmatch_table[DETECT_HTTP2_FRAMETYPE].Setup = DetectHTTP2frametypeSetup;
sigmatch_table[DETECT_HTTP2_FRAMETYPE].Free = DetectHTTP2frametypeFree; sigmatch_table[DETECT_HTTP2_FRAMETYPE].Free = DetectHTTP2frametypeFree;
sigmatch_table[DETECT_HTTP2_FRAMETYPE].flags =
SIGMATCH_INFO_UINT8 | SIGMATCH_INFO_MULTI_UINT | SIGMATCH_INFO_ENUM_UINT;
#ifdef UNITTESTS #ifdef UNITTESTS
sigmatch_table[DETECT_HTTP2_FRAMETYPE].RegisterTests = DetectHTTP2frameTypeRegisterTests; sigmatch_table[DETECT_HTTP2_FRAMETYPE].RegisterTests = DetectHTTP2frameTypeRegisterTests;
#endif #endif
@ -132,8 +134,7 @@ void DetectHttp2Register(void)
sigmatch_table[DETECT_HTTP2_PRIORITY].AppLayerTxMatch = DetectHTTP2priorityMatch; sigmatch_table[DETECT_HTTP2_PRIORITY].AppLayerTxMatch = DetectHTTP2priorityMatch;
sigmatch_table[DETECT_HTTP2_PRIORITY].Setup = DetectHTTP2prioritySetup; sigmatch_table[DETECT_HTTP2_PRIORITY].Setup = DetectHTTP2prioritySetup;
sigmatch_table[DETECT_HTTP2_PRIORITY].Free = DetectHTTP2priorityFree; sigmatch_table[DETECT_HTTP2_PRIORITY].Free = DetectHTTP2priorityFree;
sigmatch_table[DETECT_HTTP2_PRIORITY].flags = sigmatch_table[DETECT_HTTP2_PRIORITY].flags = SIGMATCH_INFO_UINT8 | SIGMATCH_INFO_MULTI_UINT;
SIGMATCH_INFO_UINT8 | SIGMATCH_INFO_MULTI_UINT | SIGMATCH_INFO_MULTI_UINT;
#ifdef UNITTESTS #ifdef UNITTESTS
sigmatch_table[DETECT_HTTP2_PRIORITY].RegisterTests = DetectHTTP2priorityRegisterTests; sigmatch_table[DETECT_HTTP2_PRIORITY].RegisterTests = DetectHTTP2priorityRegisterTests;
#endif #endif
@ -216,26 +217,7 @@ static int DetectHTTP2frametypeMatch(DetectEngineThreadCtx *det_ctx,
const SigMatchCtx *ctx) const SigMatchCtx *ctx)
{ {
uint8_t *detect = (uint8_t *)ctx; return SCHttp2TxHasFrametype(txv, flags, ctx);
return SCHttp2TxHasFrametype(txv, flags, *detect);
}
static int DetectHTTP2FuncParseFrameType(const char *str, uint8_t *ft)
{
// first parse numeric value
if (ByteExtractStringUint8(ft, 10, (uint16_t)strlen(str), str) > 0) {
return 1;
}
// it it failed so far, parse string value from enumeration
int r = SCHttp2ParseFrametype(str);
if (r >= 0 && r <= UINT8_MAX) {
*ft = (uint8_t)r;
return 1;
}
return 0;
} }
/** /**
@ -250,24 +232,16 @@ static int DetectHTTP2FuncParseFrameType(const char *str, uint8_t *ft)
*/ */
static int DetectHTTP2frametypeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) static int DetectHTTP2frametypeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
{ {
uint8_t frame_type;
if (SCDetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0) if (SCDetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
return -1; return -1;
if (!DetectHTTP2FuncParseFrameType(str, &frame_type)) { void *dua8 = SCHttp2ParseFrametype(str);
SCLogError("Invalid argument \"%s\" supplied to http2.frametype keyword.", str); if (dua8 == NULL)
return -1; return -1;
}
uint8_t *http2ft = SCCalloc(1, sizeof(uint8_t)); if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_FRAMETYPE, (SigMatchCtx *)dua8,
if (http2ft == NULL)
return -1;
*http2ft = frame_type;
if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_HTTP2_FRAMETYPE, (SigMatchCtx *)http2ft,
g_http2_match_buffer_id) == NULL) { g_http2_match_buffer_id) == NULL) {
DetectHTTP2frametypeFree(NULL, http2ft); DetectHTTP2frametypeFree(NULL, dua8);
return -1; return -1;
} }
@ -281,7 +255,7 @@ static int DetectHTTP2frametypeSetup (DetectEngineCtx *de_ctx, Signature *s, con
*/ */
void DetectHTTP2frametypeFree(DetectEngineCtx *de_ctx, void *ptr) void DetectHTTP2frametypeFree(DetectEngineCtx *de_ctx, void *ptr)
{ {
SCFree(ptr); SCDetectU8ArrayFree(ptr);
} }
/** /**

Loading…
Cancel
Save