diff --git a/doc/userguide/rules/header-keywords.rst b/doc/userguide/rules/header-keywords.rst index 3697b30d00..e3111e0a31 100644 --- a/doc/userguide/rules/header-keywords.rst +++ b/doc/userguide/rules/header-keywords.rst @@ -325,9 +325,10 @@ The following modifiers can be set to change the match criteria: ======== =================================== Modifier Description ======== =================================== -``+`` match on the bits, plus any others +``+`` match on all the bits, plus any others ``*`` match if any of the bits are set -``!`` match if the bits are not set +``!`` match if the bits are not set (or ``-``) +``=`` match on all the bits, and only them ======== =================================== To handle writing rules for session initiation packets such as ECN where a SYN @@ -335,6 +336,8 @@ packet is sent with CWR and ECE flags set, an option mask may be used by appending a comma and masked values. For example, a rule that checks for a SYN flag, regardless of the values of the reserved bits is ``tcp.flags:S,CE;`` +tcp.flags uses an :ref:`unsigned 8-bits integer ` with bitmasks. + Format of tcp.flags:: tcp.flags:[modifier][,]; diff --git a/rust/src/detect/mod.rs b/rust/src/detect/mod.rs index e6b51ed052..fdf6c60291 100644 --- a/rust/src/detect/mod.rs +++ b/rust/src/detect/mod.rs @@ -29,6 +29,7 @@ pub mod iprep; pub mod parser; pub mod requires; pub mod stream_size; +pub mod tcp; pub mod tojson; pub mod transforms; pub mod uint; diff --git a/rust/src/detect/tcp.rs b/rust/src/detect/tcp.rs new file mode 100644 index 0000000000..d77e4852c7 --- /dev/null +++ b/rust/src/detect/tcp.rs @@ -0,0 +1,146 @@ +/* Copyright (C) 2025 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::detect::uint::{ + detect_parse_uint, parse_bitchars_modifier, DetectBitflagModifier, DetectUintData, + DetectUintMode, +}; +use crate::detect::EnumString; +use nom7::bytes::complete::take; +use nom7::error::Error; + +use std::ffi::CStr; + +#[repr(u8)] +#[derive(EnumStringU8)] +#[allow(non_camel_case_types)] +enum TcpFlag { + C = 0x80, + E = 0x40, + U = 0x20, + A = 0x10, + P = 0x08, + R = 0x04, + S = 0x02, + F = 0x01, +} + +pub fn tcp_flags_parse(s: &str) -> Option> { + // first try numeric form + if let Ok((_, ctx)) = detect_parse_uint::(s) { + return Some(ctx); + } + // otherwise, try strings + let mut modifier = DetectBitflagModifier::Equal; + let mut modset = false; + let mut ignoring = false; + let mut arg1 = 0u8; + let mut arg2 = 0xffu8; + let mut s2 = s; + while !s2.is_empty() { + let (s, vals) = take::>(1usize)(s2).ok()?; + s2 = s; + let vals = match vals { + "1" => "C", + "2" => "E", + _ => vals, + }; + if vals == "," { + if ignoring { + SCLogError!("Too many commas"); + return None; + } + ignoring = true; + } else if let Some(enum_val) = TcpFlag::from_str(vals) { + let val = enum_val.into_u(); + if (arg1 & val) != 0 { + SCLogError!("Repeated bitflag for {}", vals); + return None; + } + if ignoring { + arg2 &= 0xff ^ val; + } else { + arg1 |= val; + } + } else if let Ok((rems, newmod)) = + parse_bitchars_modifier(vals, DetectBitflagModifier::Equal) + { + if !rems.is_empty() { + SCLogError!("Bad character {} for tcp.flags", vals); + return None; + } + if modset || ignoring { + SCLogError!("Cannot have multiple modifiers"); + return None; + } + modifier = newmod; + modset = true; + } // else unreachable + } + let ctx = match modifier { + DetectBitflagModifier::Equal => DetectUintData:: { + arg1: arg2, + arg2: arg1, + mode: DetectUintMode::DetectUintModeBitmask, + }, + DetectBitflagModifier::Plus => DetectUintData:: { + arg1, + arg2: arg1, + mode: DetectUintMode::DetectUintModeBitmask, + }, + DetectBitflagModifier::Any => DetectUintData:: { + arg1, + arg2: 0, + mode: DetectUintMode::DetectUintModeNegBitmask, + }, + DetectBitflagModifier::Not => DetectUintData:: { + arg1, + arg2: arg1, + mode: DetectUintMode::DetectUintModeNegBitmask, + }, + }; + return Some(ctx); +} + +#[no_mangle] +pub unsafe extern "C" fn SCDetectTcpFlagsParse( + ustr: *const std::os::raw::c_char, +) -> *mut DetectUintData { + let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe + if let Ok(s) = ft_name.to_str() { + if let Some(ctx) = tcp_flags_parse(s) { + let boxed = Box::new(ctx); + return Box::into_raw(boxed) as *mut _; + } + } + return std::ptr::null_mut(); +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn fragbits_parse() { + let ctx = tcp_flags_parse("S").unwrap(); + assert_eq!(ctx.arg2, 2); + assert!(tcp_flags_parse("G").is_none()); + assert!(tcp_flags_parse("+S*").is_none()); + let ctx = tcp_flags_parse("CE").unwrap(); + assert_eq!(ctx.arg2, 0xC0); + } +} diff --git a/rust/src/detect/uint.rs b/rust/src/detect/uint.rs index 39348e8809..40e5f6b374 100644 --- a/rust/src/detect/uint.rs +++ b/rust/src/detect/uint.rs @@ -442,7 +442,7 @@ pub enum DetectBitflagModifier { Not, } -fn parse_bitchars_modifier( +pub(crate) fn parse_bitchars_modifier( s: &str, default: DetectBitflagModifier, ) -> IResult<&str, DetectBitflagModifier> { let (s1, m) = anychar(s)?; diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 091bf72c4e..f1e9523b44 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -1701,8 +1701,7 @@ void EngineAnalysisRules(const DetectEngineCtx *de_ctx, } } else if (sm->type == DETECT_FLAGS) { - DetectFlagsData *fd = (DetectFlagsData *)sm->ctx; - if (fd != NULL) { + if (sm->ctx != NULL) { rule_flags = 1; } } diff --git a/src/detect-engine-build.c b/src/detect-engine-build.c index f356e5beff..4c6278bce4 100644 --- a/src/detect-engine-build.c +++ b/src/detect-engine-build.c @@ -479,16 +479,25 @@ static int SignatureCreateMask(Signature *s) break; case DETECT_FLAGS: { - DetectFlagsData *fl = (DetectFlagsData *)sm->ctx; - - if (fl->flags & MASK_TCP_INITDEINIT_FLAGS) { + DetectU8Data *fl = (DetectU8Data *)sm->ctx; + + uint8_t arg = 0; + if (fl->mode == DetectUintModeBitmask) { + arg = fl->arg2; + } else if (fl->mode == DetectUintModeNegBitmask && fl->arg2 == 0) { + arg = fl->arg1; + } else if (fl->mode == DetectUintModeEqual) { + arg = fl->arg1; + } + if (arg & MASK_TCP_INITDEINIT_FLAGS) { s->mask |= SIG_MASK_REQUIRE_FLAGS_INITDEINIT; SCLogDebug("sig requires SIG_MASK_REQUIRE_FLAGS_INITDEINIT"); } - if (fl->flags & MASK_TCP_UNUSUAL_FLAGS) { + if (arg & MASK_TCP_UNUSUAL_FLAGS) { s->mask |= SIG_MASK_REQUIRE_FLAGS_UNUSUAL; SCLogDebug("sig requires SIG_MASK_REQUIRE_FLAGS_UNUSUAL"); } + break; } case DETECT_DSIZE: diff --git a/src/detect-tcp-flags.c b/src/detect-tcp-flags.c index 73284cd65e..3b7092f75b 100644 --- a/src/detect-tcp-flags.c +++ b/src/detect-tcp-flags.c @@ -26,11 +26,13 @@ #include "suricata-common.h" #include "suricata.h" #include "decode.h" +#include "rust.h" #include "detect.h" #include "detect-parse.h" #include "detect-engine-prefilter.h" #include "detect-engine-prefilter-common.h" +#include "detect-engine-uint.h" #include "flow-var.h" #include "decode-events.h" @@ -41,23 +43,6 @@ #include "util-debug.h" -/** - * Regex (by Brian Rectanus) - * flags: [!+*](SAPRFU120)[,SAPRFU12] - */ -#define PARSE_REGEX "^\\s*(?:([\\+\\*!]))?\\s*([SAPRFU120CE\\+\\*!]+)(?:\\s*,\\s*([SAPRFU12CE]+))?\\s*$" - -/** - * Flags args[0] *(3) +(2) !(1) - * - */ - -#define MODIFIER_NOT 1 -#define MODIFIER_PLUS 2 -#define MODIFIER_ANY 3 - -static DetectParseRegex parse_regex; - static int DetectFlagsMatch (DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); static int DetectFlagsSetup (DetectEngineCtx *, Signature *, const char *); @@ -88,50 +73,8 @@ void DetectFlagsRegister (void) #endif sigmatch_table[DETECT_FLAGS].SupportsPrefilter = PrefilterTcpFlagsIsPrefilterable; sigmatch_table[DETECT_FLAGS].SetupPrefilter = PrefilterSetupTcpFlags; - - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); -} - -static inline int FlagsMatch(const uint8_t pflags, const uint8_t modifier, - const uint8_t dflags, const uint8_t iflags) -{ - if (!dflags && pflags) { - if(modifier == MODIFIER_NOT) { - SCReturnInt(1); - } - - SCReturnInt(0); - } - - const uint8_t flags = pflags & iflags; - - switch (modifier) { - case MODIFIER_ANY: - if ((flags & dflags) > 0) { - SCReturnInt(1); - } - SCReturnInt(0); - - case MODIFIER_PLUS: - if (((flags & dflags) == dflags)) { - SCReturnInt(1); - } - SCReturnInt(0); - - case MODIFIER_NOT: - if ((flags & dflags) != dflags) { - SCReturnInt(1); - } - SCReturnInt(0); - - default: - SCLogDebug("flags %"PRIu8" and de->flags %"PRIu8"", flags, dflags); - if (flags == dflags) { - SCReturnInt(1); - } - } - - SCReturnInt(0); + sigmatch_table[DETECT_FLAGS].flags = SIGMATCH_INFO_UINT8 | SIGMATCH_INFO_BITFLAGS_UINT; + ; } /** @@ -157,315 +100,10 @@ static int DetectFlagsMatch (DetectEngineThreadCtx *det_ctx, Packet *p, SCReturnInt(0); } - const DetectFlagsData *de = (const DetectFlagsData *)ctx; const TCPHdr *tcph = PacketGetTCP(p); const uint8_t flags = tcph->th_flags; - - return FlagsMatch(flags, de->modifier, de->flags, de->ignored_flags); -} - -/** - * \internal - * \brief This function is used to parse flags options passed via flags: keyword - * - * \param rawstr Pointer to the user provided flags options - * - * \retval de pointer to DetectFlagsData on success - * \retval NULL on failure - */ -static DetectFlagsData *DetectFlagsParse (const char *rawstr) -{ - SCEnter(); - - int found = 0, ignore = 0; - char *ptr; - DetectFlagsData *de = NULL; - - char arg1[16] = ""; - char arg2[16] = ""; - char arg3[16] = ""; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); - SCLogDebug("input '%s', pcre said %d", rawstr, ret); - if (ret < 3) { - SCLogError("pcre match failed"); - goto error; - } - - size_t pcre2len = sizeof(arg1); - int res = SC_Pcre2SubstringCopy(match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - if (ret >= 2) { - pcre2len = sizeof(arg2); - res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)arg2, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - } - if (ret >= 3) { - pcre2len = sizeof(arg3); - res = SC_Pcre2SubstringCopy(match, 3, (PCRE2_UCHAR8 *)arg3, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - } - SCLogDebug("args '%s', '%s', '%s'", arg1, arg2, arg3); - - if (strlen(arg2) == 0) { - SCLogDebug("empty argument"); - goto error; - } - - de = SCCalloc(1, sizeof(DetectFlagsData)); - if (unlikely(de == NULL)) - goto error; - de->ignored_flags = 0xff; - - /** First parse args1 */ - ptr = arg1; - while (*ptr != '\0') { - switch (*ptr) { - case 'S': - case 's': - de->flags |= TH_SYN; - found++; - break; - case 'A': - case 'a': - de->flags |= TH_ACK; - found++; - break; - case 'F': - case 'f': - de->flags |= TH_FIN; - found++; - break; - case 'R': - case 'r': - de->flags |= TH_RST; - found++; - break; - case 'P': - case 'p': - de->flags |= TH_PUSH; - found++; - break; - case 'U': - case 'u': - de->flags |= TH_URG; - found++; - break; - case '1': - de->flags |= TH_CWR; - found++; - break; - case '2': - de->flags |= TH_ECN; - found++; - break; - case 'C': - case 'c': - de->flags |= TH_CWR; - found++; - break; - case 'E': - case 'e': - de->flags |= TH_ECN; - found++; - break; - case '0': - de->flags = 0; - found++; - break; - - case '!': - de->modifier = MODIFIER_NOT; - break; - case '+': - de->modifier = MODIFIER_PLUS; - break; - case '*': - de->modifier = MODIFIER_ANY; - break; - } - ptr++; - } - - /** Second parse first set of flags */ - if (strlen(arg2) > 0) { - ptr = arg2; - while (*ptr != '\0') { - switch (*ptr) { - case 'S': - case 's': - de->flags |= TH_SYN; - found++; - break; - case 'A': - case 'a': - de->flags |= TH_ACK; - found++; - break; - case 'F': - case 'f': - de->flags |= TH_FIN; - found++; - break; - case 'R': - case 'r': - de->flags |= TH_RST; - found++; - break; - case 'P': - case 'p': - de->flags |= TH_PUSH; - found++; - break; - case 'U': - case 'u': - de->flags |= TH_URG; - found++; - break; - case '1': - case 'C': - case 'c': - de->flags |= TH_CWR; - found++; - break; - case '2': - case 'E': - case 'e': - de->flags |= TH_ECN; - found++; - break; - case '0': - de->flags = 0; - found++; - break; - - case '!': - if (de->modifier != 0) { - SCLogError("\"flags\" supports only" - " one modifier at a time"); - goto error; - } - de->modifier = MODIFIER_NOT; - SCLogDebug("NOT modifier is set"); - break; - case '+': - if (de->modifier != 0) { - SCLogError("\"flags\" supports only" - " one modifier at a time"); - goto error; - } - de->modifier = MODIFIER_PLUS; - SCLogDebug("PLUS modifier is set"); - break; - case '*': - if (de->modifier != 0) { - SCLogError("\"flags\" supports only" - " one modifier at a time"); - goto error; - } - de->modifier = MODIFIER_ANY; - SCLogDebug("ANY modifier is set"); - break; - default: - break; - } - ptr++; - } - - if (found == 0) - goto error; - } - - /** Finally parse ignored flags */ - if (strlen(arg3) > 0) { - ptr = arg3; - - while (*ptr != '\0') { - switch (*ptr) { - case 'S': - case 's': - de->ignored_flags &= ~TH_SYN; - ignore++; - break; - case 'A': - case 'a': - de->ignored_flags &= ~TH_ACK; - ignore++; - break; - case 'F': - case 'f': - de->ignored_flags &= ~TH_FIN; - ignore++; - break; - case 'R': - case 'r': - de->ignored_flags &= ~TH_RST; - ignore++; - break; - case 'P': - case 'p': - de->ignored_flags &= ~TH_PUSH; - ignore++; - break; - case 'U': - case 'u': - de->ignored_flags &= ~TH_URG; - ignore++; - break; - case '1': - de->ignored_flags &= ~TH_CWR; - ignore++; - break; - case '2': - de->ignored_flags &= ~TH_ECN; - ignore++; - break; - case 'C': - case 'c': - de->ignored_flags &= ~TH_CWR; - ignore++; - break; - case 'E': - case 'e': - de->ignored_flags &= ~TH_ECN; - ignore++; - break; - case '0': - break; - default: - break; - } - ptr++; - } - - if (ignore == 0) { - SCLogDebug("ignore == 0"); - goto error; - } - } - - pcre2_match_data_free(match); - SCLogDebug("found %"PRId32" ignore %"PRId32"", found, ignore); - SCReturnPtr(de, "DetectFlagsData"); - -error: - if (de) { - SCFree(de); - } - if (match) { - pcre2_match_data_free(match); - } - SCReturnPtr(NULL, "DetectFlagsData"); + DetectU8Data *du8 = (DetectU8Data *)ctx; + return DetectU8Match(flags, du8); } /** @@ -482,14 +120,12 @@ error: */ static int DetectFlagsSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) { - DetectFlagsData *de = NULL; - - de = DetectFlagsParse(rawstr); - if (de == NULL) + DetectU8Data *du8 = SCDetectTcpFlagsParse(rawstr); + if (du8 == NULL) goto error; if (SCSigMatchAppendSMToList( - de_ctx, s, DETECT_FLAGS, (SigMatchCtx *)de, DETECT_SM_LIST_MATCH) == NULL) { + de_ctx, s, DETECT_FLAGS, (SigMatchCtx *)du8, DETECT_SM_LIST_MATCH) == NULL) { goto error; } s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -497,21 +133,20 @@ static int DetectFlagsSetup (DetectEngineCtx *de_ctx, Signature *s, const char * return 0; error: - if (de) - SCFree(de); + if (du8) + DetectFlagsFree(NULL, du8); return -1; } /** * \internal - * \brief this function will free memory associated with DetectFlagsData + * \brief this function will free memory associated with DetectU8Data * - * \param de pointer to DetectFlagsData + * \param de pointer to DetectU8Data */ static void DetectFlagsFree(DetectEngineCtx *de_ctx, void *de_ptr) { - DetectFlagsData *de = (DetectFlagsData *)de_ptr; - if(de) SCFree(de); + SCDetectU8Free(de_ptr); } int DetectFlagsSignatureNeedsSynPackets(const Signature *s) @@ -521,9 +156,9 @@ int DetectFlagsSignatureNeedsSynPackets(const Signature *s) switch (sm->type) { case DETECT_FLAGS: { - const DetectFlagsData *fl = (const DetectFlagsData *)sm->ctx; + const DetectU8Data *fl = (const DetectU8Data *)sm->ctx; - if (!(fl->modifier == MODIFIER_NOT) && (fl->flags & TH_SYN)) { + if (DetectU8Match(TH_SYN, fl)) { return 1; } break; @@ -540,9 +175,9 @@ int DetectFlagsSignatureNeedsSynOnlyPackets(const Signature *s) switch (sm->type) { case DETECT_FLAGS: { - const DetectFlagsData *fl = (const DetectFlagsData *)sm->ctx; + const DetectU8Data *fl = (const DetectU8Data *)sm->ctx; - if (!(fl->modifier == MODIFIER_NOT) && (fl->flags == TH_SYN)) { + if (!(fl->mode == DetectUintModeNegBitmask) && (fl->arg1 == TH_SYN)) { return 1; } break; @@ -566,8 +201,11 @@ PrefilterPacketFlagsMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void const TCPHdr *tcph = PacketGetTCP(p); const uint8_t flags = tcph->th_flags; - if (FlagsMatch(flags, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2])) - { + DetectU8Data du8; + du8.mode = ctx->v1.u8[0]; + du8.arg1 = ctx->v1.u8[1]; + du8.arg2 = ctx->v1.u8[2]; + if (DetectU8Match(flags, &du8)) { SCLogDebug("packet matches TCP flags %02x", ctx->v1.u8[1]); PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); } @@ -576,20 +214,18 @@ PrefilterPacketFlagsMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void static void PrefilterPacketFlagsSet(PrefilterPacketHeaderValue *v, void *smctx) { - const DetectFlagsData *a = smctx; - v->u8[0] = a->modifier; - v->u8[1] = a->flags; - v->u8[2] = a->ignored_flags; + const DetectU8Data *a = smctx; + v->u8[0] = a->mode; + v->u8[1] = a->arg1; + v->u8[2] = a->arg2; SCLogDebug("v->u8[0] = %02x", v->u8[0]); } static bool PrefilterPacketFlagsCompare(PrefilterPacketHeaderValue v, void *smctx) { - const DetectFlagsData *a = smctx; - if (v.u8[0] == a->modifier && - v.u8[1] == a->flags && - v.u8[2] == a->ignored_flags) + const DetectU8Data *a = smctx; + if (v.u8[0] == a->mode && v.u8[1] == a->arg1 && v.u8[2] == a->arg2) return true; return false; } @@ -617,39 +253,6 @@ static bool PrefilterTcpFlagsIsPrefilterable(const Signature *s) */ #ifdef UNITTESTS -/** - * \test FlagsTestParse01 is a test for a valid flags value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int FlagsTestParse01 (void) -{ - DetectFlagsData *de = DetectFlagsParse("S"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(de->flags == TH_SYN); - DetectFlagsFree(NULL, de); - PASS; -} - -/** - * \test FlagsTestParse02 is a test for an invalid flags value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int FlagsTestParse02 (void) -{ - DetectFlagsData *de = NULL; - de = DetectFlagsParse("G"); - if (de) { - DetectFlagsFree(NULL, de); - return 0; - } - - return 1; -} - /** * \test FlagsTestParse03 test if ACK and PUSH are set. Must return success * @@ -672,9 +275,11 @@ static int FlagsTestParse03 (void) tcph.th_flags = TH_ACK | TH_PUSH | TH_SYN | TH_RST; UTHSetTCPHdr(p, &tcph); - DetectFlagsData *de = DetectFlagsParse("AP+"); + DetectU8Data *de = SCDetectTcpFlagsParse("AP+"); FAIL_IF_NULL(de); - FAIL_IF(de->flags != (TH_ACK | TH_PUSH)); + FAIL_IF(de->mode != DetectUintModeBitmask); + FAIL_IF(de->arg1 != (TH_ACK | TH_PUSH)); + FAIL_IF(de->arg2 != (TH_ACK | TH_PUSH)); SigMatch *sm = SigMatchAlloc(); FAIL_IF_NULL(sm); @@ -711,9 +316,11 @@ static int FlagsTestParse04 (void) tcph.th_flags = TH_SYN; UTHSetTCPHdr(p, &tcph); - DetectFlagsData *de = DetectFlagsParse("A"); + DetectU8Data *de = SCDetectTcpFlagsParse("A"); FAIL_IF_NULL(de); - FAIL_IF(de->flags != TH_ACK); + FAIL_IF(de->mode != DetectUintModeBitmask); + FAIL_IF(de->arg1 != 0xFF); + FAIL_IF(de->arg2 != TH_ACK); SigMatch *sm = SigMatchAlloc(); FAIL_IF_NULL(sm); @@ -749,11 +356,11 @@ static int FlagsTestParse05 (void) tcph.th_flags = TH_ACK | TH_PUSH | TH_SYN | TH_RST; UTHSetTCPHdr(p, &tcph); - DetectFlagsData *de = DetectFlagsParse("+AP,SR"); + DetectU8Data *de = SCDetectTcpFlagsParse("+AP,SR"); FAIL_IF_NULL(de); - FAIL_IF(de->modifier != MODIFIER_PLUS); - FAIL_IF(de->flags != (TH_ACK | TH_PUSH)); - FAIL_IF(de->ignored_flags != (uint8_t) ~(TH_SYN | TH_RST)); + FAIL_IF(de->mode != DetectUintModeBitmask); + FAIL_IF(de->arg1 != (TH_ACK | TH_PUSH)); + FAIL_IF(de->arg2 != (TH_ACK | TH_PUSH)); SigMatch *sm = SigMatchAlloc(); FAIL_IF_NULL(sm); @@ -790,12 +397,11 @@ static int FlagsTestParse06 (void) tcph.th_flags = TH_ACK | TH_PUSH | TH_SYN | TH_RST; UTHSetTCPHdr(p, &tcph); - DetectFlagsData *de = DetectFlagsParse("+AP,UR"); + DetectU8Data *de = SCDetectTcpFlagsParse("+AP,UR"); FAIL_IF_NULL(de); - - FAIL_IF(de->modifier != MODIFIER_PLUS); - FAIL_IF(de->flags != (TH_ACK | TH_PUSH)); - FAIL_IF((0xff - de->ignored_flags) != (TH_URG | TH_RST)); + FAIL_IF(de->mode != DetectUintModeBitmask); + FAIL_IF(de->arg1 != (TH_ACK | TH_PUSH)); + FAIL_IF(de->arg2 != (TH_ACK | TH_PUSH)); SigMatch *sm = SigMatchAlloc(); FAIL_IF_NULL(sm); @@ -832,12 +438,11 @@ static int FlagsTestParse07 (void) tcph.th_flags = TH_SYN | TH_RST; UTHSetTCPHdr(p, &tcph); - DetectFlagsData *de = DetectFlagsParse("*AP"); - FAIL_IF_NULL(de); - + DetectU8Data *de = SCDetectTcpFlagsParse("*AP"); FAIL_IF_NULL(de); - FAIL_IF(de->modifier != MODIFIER_ANY); - FAIL_IF(de->flags != (TH_ACK | TH_PUSH)); + FAIL_IF(de->mode != DetectUintModeNegBitmask); + FAIL_IF(de->arg1 != (TH_ACK | TH_PUSH)); + FAIL_IF(de->arg2 != 0); SigMatch *sm = SigMatchAlloc(); FAIL_IF_NULL(sm); @@ -874,10 +479,10 @@ static int FlagsTestParse08 (void) tcph.th_flags = TH_SYN | TH_RST; UTHSetTCPHdr(p, &tcph); - DetectFlagsData *de = DetectFlagsParse("*SA"); + DetectU8Data *de = SCDetectTcpFlagsParse("*SA"); FAIL_IF_NULL(de); - FAIL_IF(de->modifier != MODIFIER_ANY); - FAIL_IF(de->flags != (TH_ACK | TH_SYN)); + FAIL_IF(de->mode != DetectUintModeNegBitmask); + FAIL_IF(de->arg1 != (TH_ACK | TH_SYN)); SigMatch *sm = SigMatchAlloc(); FAIL_IF_NULL(sm); @@ -914,10 +519,11 @@ static int FlagsTestParse09 (void) tcph.th_flags = TH_SYN | TH_RST; UTHSetTCPHdr(p, &tcph); - DetectFlagsData *de = DetectFlagsParse("!PA"); + DetectU8Data *de = SCDetectTcpFlagsParse("!PA"); FAIL_IF_NULL(de); - FAIL_IF(de->modifier != MODIFIER_NOT); - FAIL_IF(de->flags != (TH_ACK | TH_PUSH)); + FAIL_IF(de->mode != DetectUintModeNegBitmask); + FAIL_IF(de->arg1 != (TH_ACK | TH_PUSH)); + FAIL_IF(de->arg2 != (TH_ACK | TH_PUSH)); SigMatch *sm = SigMatchAlloc(); FAIL_IF_NULL(sm); @@ -954,11 +560,11 @@ static int FlagsTestParse10 (void) tcph.th_flags = TH_SYN | TH_RST; UTHSetTCPHdr(p, &tcph); - DetectFlagsData *de = DetectFlagsParse("!AP"); + DetectU8Data *de = SCDetectTcpFlagsParse("!AP"); FAIL_IF_NULL(de); - FAIL_IF(de->modifier != MODIFIER_NOT); - FAIL_IF(de->flags != (TH_ACK | TH_PUSH)); + FAIL_IF(de->mode != DetectUintModeNegBitmask); + FAIL_IF(de->arg1 != (TH_ACK | TH_PUSH)); SigMatch *sm = SigMatchAlloc(); FAIL_IF_NULL(sm); @@ -995,11 +601,11 @@ static int FlagsTestParse11 (void) tcph.th_flags = TH_SYN | TH_RST | TH_URG; UTHSetTCPHdr(p, &tcph); - DetectFlagsData *de = DetectFlagsParse("*AP,SR"); + DetectU8Data *de = SCDetectTcpFlagsParse("*AP,SR"); FAIL_IF_NULL(de); - FAIL_IF(de->modifier != MODIFIER_ANY); - FAIL_IF(de->flags != (TH_ACK | TH_PUSH)); - FAIL_IF(de->ignored_flags != (uint8_t) ~(TH_SYN | TH_RST)); + FAIL_IF(de->mode != DetectUintModeNegBitmask); + FAIL_IF(de->arg1 != (TH_ACK | TH_PUSH)); + FAIL_IF(de->arg2 != 0); SigMatch *sm = SigMatchAlloc(); FAIL_IF_NULL(de); @@ -1036,10 +642,10 @@ static int FlagsTestParse12 (void) tcph.th_flags = TH_SYN; UTHSetTCPHdr(p, &tcph); - DetectFlagsData *de = DetectFlagsParse("0"); + DetectU8Data *de = SCDetectTcpFlagsParse("0"); FAIL_IF_NULL(de); - FAIL_IF_NOT(de->modifier == 0); - FAIL_IF_NOT(de->flags == 0); + FAIL_IF_NOT(de->mode == DetectUintModeEqual); + FAIL_IF_NOT(de->arg1 == 0); SigMatch *sm = SigMatchAlloc(); FAIL_IF_NULL(sm); @@ -1054,34 +660,6 @@ static int FlagsTestParse12 (void) PASS; } -/** - * \test test for a invalid flags value - * - * \retval 1 on success - * \retval 0 on failure - */ -static int FlagsTestParse13 (void) -{ - DetectFlagsData *de = DetectFlagsParse("+S*"); - FAIL_IF_NOT(de == NULL); - PASS; -} - -/** - * \test Parse 'C' and 'E' flags. - * - * \retval 1 on success. - * \retval 0 on failure. - */ -static int FlagsTestParse14(void) -{ - DetectFlagsData *de = DetectFlagsParse("CE"); - FAIL_IF_NULL(de); - FAIL_IF_NOT(de->flags == (TH_CWR | TH_ECN)); - DetectFlagsFree(NULL, de); - PASS; -} - static int FlagsTestParse15(void) { ThreadVars tv; @@ -1098,9 +676,11 @@ static int FlagsTestParse15(void) tcph.th_flags = TH_ECN | TH_CWR | TH_SYN | TH_RST; UTHSetTCPHdr(p, &tcph); - DetectFlagsData *de = de = DetectFlagsParse("EC+"); + DetectU8Data *de = SCDetectTcpFlagsParse("EC+"); FAIL_IF_NULL(de); - FAIL_IF_NOT(de->flags == (TH_ECN | TH_CWR)); + FAIL_IF_NOT(de->mode == DetectUintModeBitmask); + FAIL_IF_NOT(de->arg1 == (TH_ECN | TH_CWR)); + FAIL_IF_NOT(de->arg2 == (TH_ECN | TH_CWR)); SigMatch *sm = SigMatchAlloc(); FAIL_IF_NULL(sm); @@ -1131,9 +711,11 @@ static int FlagsTestParse16(void) tcph.th_flags = TH_ECN | TH_SYN | TH_RST; UTHSetTCPHdr(p, &tcph); - DetectFlagsData *de = DetectFlagsParse("EC*"); + DetectU8Data *de = SCDetectTcpFlagsParse("EC*"); FAIL_IF_NULL(de); - FAIL_IF_NOT(de->flags == (TH_ECN | TH_CWR)); + FAIL_IF_NOT(de->mode == DetectUintModeNegBitmask); + FAIL_IF_NOT(de->arg1 == (TH_ECN | TH_CWR)); + FAIL_IF_NOT(de->arg2 == 0); SigMatch *sm = SigMatchAlloc(); FAIL_IF_NULL(sm); @@ -1168,9 +750,11 @@ static int FlagsTestParse17(void) tcph.th_flags = TH_ECN | TH_SYN | TH_RST; UTHSetTCPHdr(p, &tcph); - DetectFlagsData *de = DetectFlagsParse("EC+"); + DetectU8Data *de = SCDetectTcpFlagsParse("EC+"); FAIL_IF_NULL(de); - FAIL_IF_NOT(de->flags == (TH_ECN | TH_CWR)); + FAIL_IF_NOT(de->mode == DetectUintModeBitmask); + FAIL_IF_NOT(de->arg1 == (TH_ECN | TH_CWR)); + FAIL_IF_NOT(de->arg2 == (TH_ECN | TH_CWR)); SigMatch *sm = SigMatchAlloc(); FAIL_IF_NULL(sm); @@ -1190,8 +774,6 @@ static int FlagsTestParse17(void) */ static void FlagsRegisterTests(void) { - UtRegisterTest("FlagsTestParse01", FlagsTestParse01); - UtRegisterTest("FlagsTestParse02", FlagsTestParse02); UtRegisterTest("FlagsTestParse03", FlagsTestParse03); UtRegisterTest("FlagsTestParse04", FlagsTestParse04); UtRegisterTest("FlagsTestParse05", FlagsTestParse05); @@ -1202,8 +784,6 @@ static void FlagsRegisterTests(void) UtRegisterTest("FlagsTestParse10", FlagsTestParse10); UtRegisterTest("FlagsTestParse11", FlagsTestParse11); UtRegisterTest("FlagsTestParse12", FlagsTestParse12); - UtRegisterTest("FlagsTestParse13", FlagsTestParse13); - UtRegisterTest("FlagsTestParse14", FlagsTestParse14); UtRegisterTest("FlagsTestParse15", FlagsTestParse15); UtRegisterTest("FlagsTestParse16", FlagsTestParse16); UtRegisterTest("FlagsTestParse17", FlagsTestParse17); diff --git a/src/detect-tcp-flags.h b/src/detect-tcp-flags.h index 6fb7e6b0b7..f36ef01393 100644 --- a/src/detect-tcp-flags.h +++ b/src/detect-tcp-flags.h @@ -24,22 +24,6 @@ #ifndef SURICATA_DETECT_FLAGS_H #define SURICATA_DETECT_FLAGS_H -/** - * \struct DetectFlagsData_ - * DetectFlagsData_ is used to store flags: input value - */ - -/** - * \typedef DetectFlagsData - * A typedef for DetectFlagsData_ - */ - -typedef struct DetectFlagsData_ { - uint8_t flags; /**< TCP flags */ - uint8_t modifier; /**< !(1) +(2) *(3) modifiers */ - uint8_t ignored_flags; /**< Ignored TCP flags defined by modifier , */ -} DetectFlagsData; - /** * Registration function for flags: keyword */