From: Victor Julien Date: Fri, 14 Jan 2022 19:34:04 +0000 (+0100) Subject: quic: redo quic.version; parser cleanups X-Git-Tag: suricata-7.0.0-beta1~1006 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=24a21af4ab9e4bb7ebf37a42577294733dca64d8;p=thirdparty%2Fsuricata.git 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. --- diff --git a/rust/src/quic/detect.rs b/rust/src/quic/detect.rs index c5b1fe18c4..2cff8fc94b 100644 --- a/rust/src/quic/detect.rs +++ b/rust/src/quic/detect.rs @@ -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() -} diff --git a/rust/src/quic/parser.rs b/rust/src/quic/parser.rs index d3283de7cc..7888e9c995 100644 --- a/rust/src/quic/parser.rs +++ b/rust/src/quic/parser.rs @@ -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, pub dcid: Vec, pub scid: Vec, } @@ -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(), }, diff --git a/rust/src/quic/quic.rs b/rust/src/quic/quic.rs index a7a6cb5255..3fe23d6382 100644 --- a/rust/src/quic/quic.rs +++ b/rust/src/quic/quic.rs @@ -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, - - 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, diff --git a/src/detect-quic-version.c b/src/detect-quic-version.c index 12640dac92..d97f62ac1e 100644 --- a/src/detect-quic-version.c +++ b/src/detect-quic-version.c @@ -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 */