quic: redo quic.version; parser cleanups

Reimplement quic.version as sticky buffer.

Removed unused parts of the parser.

Set unidirectional tx flag to fix double matching.
pull/6819/head
Victor Julien 4 years ago
parent 6641efb74f
commit 24a21af4ab

@ -18,6 +18,22 @@
use crate::quic::quic::{QuicTransaction};
use std::ptr;
#[no_mangle]
pub unsafe extern "C" fn rs_quic_tx_get_version(
tx: &QuicTransaction, buffer: *mut *const u8, buffer_len: *mut u32,
) -> u8 {
if tx.header.flags.is_long {
let s = &tx.header.version_buf;
*buffer = s.as_ptr();
*buffer_len = s.len() as u32;
1
} else {
*buffer = ptr::null();
*buffer_len = 0;
0
}
}
#[no_mangle]
pub unsafe extern "C" fn rs_quic_tx_get_cyu_hash(
tx: &QuicTransaction, i: u32, buffer: *mut *const u8, buffer_len: *mut u32,
@ -58,8 +74,3 @@ pub unsafe extern "C" fn rs_quic_tx_get_cyu_string(
0
}
}
#[no_mangle]
pub extern "C" fn rs_quic_tx_get_version(tx: &QuicTransaction) -> u32 {
tx.header.version.into()
}

@ -76,7 +76,7 @@ pub enum QuicType {
#[derive(Debug, PartialEq)]
pub struct PublicFlags {
is_long: bool,
pub is_long: bool,
}
impl PublicFlags {
@ -93,6 +93,7 @@ pub struct QuicHeader {
pub flags: PublicFlags,
pub ty: QuicType,
pub version: QuicVersion,
pub version_buf: Vec<u8>,
pub dcid: Vec<u8>,
pub scid: Vec<u8>,
}
@ -111,6 +112,7 @@ impl QuicHeader {
flags,
ty,
version,
version_buf: Vec::new(),
dcid,
scid,
}
@ -132,12 +134,14 @@ impl QuicHeader {
flags,
ty: QuicType::Short,
version: QuicVersion(0),
version_buf: Vec::new(),
dcid: dcid.to_vec(),
scid: Vec::new(),
},
));
} else {
// Decode Long header
let (_, version_buf) = take(4_usize)(rest)?;
let (rest, version) = map(be_u32, QuicVersion)(rest)?;
let ty = if version == QuicVersion(0) {
@ -213,6 +217,7 @@ impl QuicHeader {
flags,
ty,
version,
version_buf: version_buf.to_vec(),
dcid,
scid,
},
@ -253,6 +258,7 @@ mod tests {
flags: PublicFlags { is_long: true },
ty: QuicType::Initial,
version: QuicVersion(0xff00001d),
version_buf: vec![0xff, 0x00, 0x00, 0x1d],
dcid: hex::decode("91d0b10ac886039973885dfa07c46943")
.unwrap()
.to_vec(),
@ -275,6 +281,7 @@ mod tests {
flags: PublicFlags { is_long: true },
ty: QuicType::Initial,
version: QuicVersion::Q044,
version_buf: vec![0x51, 0x30, 0x34, 0x34],
dcid: hex::decode("05cad2cc06c4d0e4").unwrap().to_vec(),
scid: Vec::new(),
},

@ -20,7 +20,7 @@ use super::{
parser::{QuicData, QuicHeader},
};
use crate::applayer::{self, *};
use crate::core::{self, AppProto, Flow, ALPROTO_FAILED, ALPROTO_UNKNOWN, IPPROTO_UDP};
use crate::core::{AppProto, Flow, ALPROTO_FAILED, ALPROTO_UNKNOWN, IPPROTO_UDP};
use std::ffi::CString;
static mut ALPROTO_QUIC: AppProto = ALPROTO_UNKNOWN;
@ -32,9 +32,6 @@ pub struct QuicTransaction {
tx_id: u64,
pub header: QuicHeader,
pub cyu: Vec<Cyu>,
de_state: Option<*mut core::DetectEngineState>,
events: *mut core::AppLayerDecoderEvents,
tx_data: AppLayerTxData,
}
@ -45,26 +42,9 @@ impl QuicTransaction {
tx_id: 0,
header,
cyu,
de_state: None,
events: std::ptr::null_mut(),
tx_data: AppLayerTxData::new(),
}
}
fn free(&mut self) {
if !self.events.is_null() {
core::sc_app_layer_decoder_events_free_events(&mut self.events);
}
if let Some(state) = self.de_state {
core::sc_detect_engine_state_free(state);
}
}
}
impl Drop for QuicTransaction {
fn drop(&mut self) {
self.free();
}
}
pub struct QuicState {
@ -231,30 +211,6 @@ pub unsafe extern "C" fn rs_quic_tx_get_alstate_progress(
return 1;
}
#[no_mangle]
pub unsafe extern "C" fn rs_quic_state_get_events(
tx: *mut std::os::raw::c_void,
) -> *mut core::AppLayerDecoderEvents {
let tx = cast_pointer!(tx, QuicTransaction);
return tx.events;
}
#[no_mangle]
pub extern "C" fn rs_quic_state_get_event_info(
_event_name: *const std::os::raw::c_char, _event_id: *mut std::os::raw::c_int,
_event_type: *mut core::AppLayerEventType,
) -> std::os::raw::c_int {
return -1;
}
#[no_mangle]
pub extern "C" fn rs_quic_state_get_event_info_by_id(
_event_id: std::os::raw::c_int, _event_name: *mut *const std::os::raw::c_char,
_event_type: *mut core::AppLayerEventType,
) -> i8 {
return -1;
}
#[no_mangle]
pub unsafe extern "C" fn rs_quic_state_get_tx_iterator(
_ipproto: u8, _alproto: AppProto, state: *mut std::os::raw::c_void, min_tx_id: u64,
@ -299,15 +255,15 @@ pub unsafe extern "C" fn rs_quic_register_parser() {
tx_comp_st_ts: 1,
tx_comp_st_tc: 1,
tx_get_progress: rs_quic_tx_get_alstate_progress,
get_eventinfo: Some(rs_quic_state_get_event_info),
get_eventinfo_byid: Some(rs_quic_state_get_event_info_by_id),
get_eventinfo: None,
get_eventinfo_byid: None,
localstorage_new: None,
localstorage_free: None,
get_files: None,
get_tx_iterator: Some(rs_quic_state_get_tx_iterator),
get_tx_data: rs_quic_get_tx_data,
apply_tx_config: None,
flags: 0,
flags: APP_LAYER_PARSER_OPT_UNIDIR_TXS,
truncate: None,
get_frame_id_by_name: None,
get_frame_name_by_id: None,

@ -25,6 +25,8 @@
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-prefilter.h"
#include "detect-engine-mpm.h"
#include "detect-engine-content-inspection.h"
#include "detect-engine-uint.h"
#include "detect-quic-version.h"
@ -36,70 +38,59 @@
static void DetectQuicVersionRegisterTests(void);
#endif
#define BUFFER_NAME "quic_version"
#define KEYWORD_NAME "quic.version"
#define KEYWORD_ID DETECT_AL_QUIC_VERSION
static int quic_version_id = 0;
static int DetectQuicVersionMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags,
void *state, void *txv, const Signature *s, const SigMatchCtx *ctx);
static int DetectQuicVersionSetup(DetectEngineCtx *, Signature *, const char *);
void DetectQuicVersionFree(DetectEngineCtx *de_ctx, void *);
static int DetectEngineInspectQuicVersionGeneric(DetectEngineCtx *de_ctx,
DetectEngineThreadCtx *det_ctx, const struct DetectEngineAppInspectionEngine_ *engine,
const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id);
static InspectionBuffer *GetVersionData(DetectEngineThreadCtx *det_ctx,
const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
const int list_id)
{
InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
if (buffer->inspect == NULL) {
uint32_t b_len = 0;
const uint8_t *b = NULL;
if (rs_quic_tx_get_version(txv, &b, &b_len) != 1)
return NULL;
if (b == NULL || b_len == 0)
return NULL;
InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len);
InspectionBufferApplyTransforms(buffer, transforms);
}
return buffer;
}
/**
* \brief Registration function for quic.version: keyword
*/
void DetectQuicVersionRegister(void)
{
sigmatch_table[DETECT_AL_QUIC_VERSION].name = "quic.version";
sigmatch_table[DETECT_AL_QUIC_VERSION].name = KEYWORD_NAME;
sigmatch_table[DETECT_AL_QUIC_VERSION].desc = "match Quic version";
sigmatch_table[DETECT_AL_QUIC_VERSION].url = "/rules/quic-keywords.html#quic-version";
sigmatch_table[DETECT_AL_QUIC_VERSION].AppLayerTxMatch = DetectQuicVersionMatch;
sigmatch_table[DETECT_AL_QUIC_VERSION].Setup = DetectQuicVersionSetup;
sigmatch_table[DETECT_AL_QUIC_VERSION].Free = DetectQuicVersionFree;
sigmatch_table[DETECT_AL_QUIC_VERSION].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
#ifdef UNITTESTS
sigmatch_table[DETECT_AL_QUIC_VERSION].RegisterTests = DetectQuicVersionRegisterTests;
#endif
DetectAppLayerInspectEngineRegister2("quic.version", ALPROTO_QUIC, SIG_FLAG_TOSERVER, 1,
DetectEngineInspectQuicVersionGeneric, NULL);
DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
GetVersionData, ALPROTO_QUIC, 1);
DetectAppLayerMpmRegister2(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister,
GetVersionData, ALPROTO_QUIC, 1);
quic_version_id = DetectBufferTypeGetByName("quic.version");
}
DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOSERVER, 1,
DetectEngineInspectBufferGeneric, GetVersionData);
DetectAppLayerInspectEngineRegister2(BUFFER_NAME, ALPROTO_QUIC, SIG_FLAG_TOCLIENT, 1,
DetectEngineInspectBufferGeneric, GetVersionData);
static int DetectEngineInspectQuicVersionGeneric(DetectEngineCtx *de_ctx,
DetectEngineThreadCtx *det_ctx, const struct DetectEngineAppInspectionEngine_ *engine,
const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
{
return DetectEngineInspectGenericList(
de_ctx, det_ctx, s, engine->smd, f, flags, alstate, txv, tx_id);
}
/**
* \internal
* \brief Function to match protocol version of an Quic Tx
*
* \param det_ctx Pointer to the pattern matcher thread.
* \param f Pointer to the current flow.
* \param flags Flags.
* \param state App layer state.
* \param txv Pointer to the transaction.
* \param s Pointer to the Signature.
* \param ctx Pointer to the sigmatch that we will cast into DetectQuicVersionData.
*
* \retval 0 no match.
* \retval 1 match.
*/
static int DetectQuicVersionMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags,
void *state, void *txv, const Signature *s, const SigMatchCtx *ctx)
{
const DetectU32Data *de = (const DetectU32Data *)ctx;
uint32_t version;
version = rs_quic_tx_get_version(txv);
return DetectU32Match(version, de);
quic_version_id = DetectBufferTypeGetByName(BUFFER_NAME);
}
/**
@ -115,45 +106,13 @@ static int DetectQuicVersionMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8
*/
static int DetectQuicVersionSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
{
SigMatch *sm = NULL;
DetectU32Data *de = NULL;
if (DetectSignatureSetAppProto(s, ALPROTO_QUIC) < 0)
if (DetectBufferSetActiveList(s, quic_version_id) < 0)
return -1;
de = DetectU32Parse(rawstr);
if (de == NULL)
if (DetectSignatureSetAppProto(s, ALPROTO_QUIC) < 0)
return -1;
sm = SigMatchAlloc();
if (sm == NULL)
goto error;
sm->type = DETECT_AL_QUIC_VERSION;
sm->ctx = (SigMatchCtx *)de;
SigMatchAppendSMToList(s, sm, quic_version_id);
return 0;
error:
if (de != NULL)
SCFree(de);
if (sm != NULL)
SCFree(sm);
return -1;
}
/**
* \internal
* \brief this function will free memory associated with DetectQuicVersionData
*
* \param de pointer to DetectQuicVersionData
*/
void DetectQuicVersionFree(DetectEngineCtx *de_ctx, void *de_ptr)
{
if (de_ptr != NULL)
SCFree(de_ptr);
}
#ifdef UNITTESTS
@ -170,35 +129,11 @@ static int QuicVersionTestParse01(void)
FAIL_IF_NULL(de_ctx);
Signature *sig = DetectEngineAppendSig(
de_ctx, "alert ip any any -> any any (quic.version:3; sid:1; rev:1;)");
FAIL_IF_NULL(sig);
sig = DetectEngineAppendSig(
de_ctx, "alert ip any any -> any any (quic.version:3; sid:2; rev:1;)");
FAIL_IF_NULL(sig);
DetectEngineCtxFree(de_ctx);
PASS;
}
/**
* \test QuicVersionTestParse02 is a test for a valid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int QuicVersionTestParse02(void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);
Signature *sig = DetectEngineAppendSig(
de_ctx, "alert ip any any -> any any (quic.version:>3; sid:1; rev:1;)");
de_ctx, "alert ip any any -> any any (quic.version; content:\"Q046\"; sid:1; rev:1;)");
FAIL_IF_NULL(sig);
sig = DetectEngineAppendSig(
de_ctx, "alert ip any any -> any any (quic.version:<44; sid:2; rev:1;)");
de_ctx, "alert ip any any -> any any (quic.version; content:\"|00|\"; sid:2; rev:1;)");
FAIL_IF_NULL(sig);
DetectEngineCtxFree(de_ctx);
@ -226,35 +161,13 @@ static int QuicVersionTestParse03(void)
PASS;
}
/**
* \test QuicVersionTestParse04 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int QuicVersionTestParse04(void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);
Signature *sig = DetectEngineAppendSig(
de_ctx, "alert ip any any -> any any (quic.version:<4294967296; sid:1; rev:1;)");
FAIL_IF_NOT_NULL(sig);
DetectEngineCtxFree(de_ctx);
PASS;
}
/**
* \brief this function registers unit tests for QuicVersion
*/
void DetectQuicVersionRegisterTests(void)
{
UtRegisterTest("QuicVersionTestParse01", QuicVersionTestParse01);
UtRegisterTest("QuicVersionTestParse02", QuicVersionTestParse02);
UtRegisterTest("QuicVersionTestParse03", QuicVersionTestParse03);
UtRegisterTest("QuicVersionTestParse04", QuicVersionTestParse04);
}
#endif /* UNITTESTS */

Loading…
Cancel
Save