detect/tcp: make tcp.flags a generic integer with bitflags

Ticket: 6724

Allows to use numerical values for example

Also fixes some unit tests that were returning 1 after goto error
FlagsTestParse05 especially took this path as
de->ignored_flags != (TH_SYN|TH_RST) was false
we had de->ignored_flags == 0xff ^ (TH_SYN|TH_RST)
And then, we had a match, instead of what the not-run code
was supposing.
pull/14067/head
Philippe Antoine 1 month ago committed by Victor Julien
parent 1f9236a6d8
commit d8cb00e795

@ -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 <rules-integer-keywords>` with bitmasks.
Format of tcp.flags::
tcp.flags:[modifier]<test flags>[,<ignore flags>];

@ -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;

@ -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<DetectUintData<u8>> {
// first try numeric form
if let Ok((_, ctx)) = detect_parse_uint::<u8>(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::<usize, &str, Error<_>>(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::<u8> {
arg1: arg2,
arg2: arg1,
mode: DetectUintMode::DetectUintModeBitmask,
},
DetectBitflagModifier::Plus => DetectUintData::<u8> {
arg1,
arg2: arg1,
mode: DetectUintMode::DetectUintModeBitmask,
},
DetectBitflagModifier::Any => DetectUintData::<u8> {
arg1,
arg2: 0,
mode: DetectUintMode::DetectUintModeNegBitmask,
},
DetectBitflagModifier::Not => DetectUintData::<u8> {
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<u8> {
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);
}
}

@ -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)?;

@ -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;
}
}

@ -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:

@ -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);

@ -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
*/

Loading…
Cancel
Save