Go to the documentation of this file.
51 #define PARSE_REGEX "^([a-z]+)(?:,\\s*(.*))?"
54 #define MAX_TOKENS 100
89 while ((token = strtok_r(arrptr,
"|", &saveptr))) {
91 while(isspace((
unsigned char)*token))
95 char *end = token + strlen(token) - 1;
96 while(end > token && isspace((
unsigned char)*end))
100 if (strchr(token,
' ') != NULL) {
101 SCLogError(
"Spaces are not allowed in flowbit names.");
107 "maximum allowed: %d.",
206 return DetectFlowbitMatchIsset(p,fd);
208 return DetectFlowbitMatchIsnotset(p,fd);
210 return DetectFlowbitMatchSet(p,fd);
212 return DetectFlowbitMatchUnset(p,fd);
214 return DetectFlowbitMatchToggle(p,fd);
223 static int DetectFlowbitParse(
const char *
str,
char *cmd,
int cmd_len,
char *
name,
228 pcre2_match_data *match = NULL;
231 if (count != 2 && count != 3) {
232 SCLogError(
"\"%s\" is not a valid setting for flowbits.",
str);
237 rc = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)cmd, &pcre2len);
239 SCLogError(
"pcre2_substring_copy_bynumber failed");
245 rc = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)
name, &pcre2len);
247 SCLogError(
"pcre2_substring_copy_bynumber failed");
252 while (strlen(
name) > 0 && isblank(
name[strlen(
name) - 1])) {
256 if (strchr(
name,
'|') == NULL) {
258 for (
size_t i = 0; i < strlen(
name); i++) {
259 if (isblank(
name[i])) {
260 SCLogError(
"spaces not allowed in flowbit names");
267 pcre2_match_data_free(match);
272 pcre2_match_data_free(match);
281 char fb_cmd_str[16] =
"", fb_name[256] =
"";
283 if (!DetectFlowbitParse(rawstr, fb_cmd_str,
sizeof(fb_cmd_str), fb_name,
288 if (strcmp(fb_cmd_str,
"noalert") == 0) {
289 if (strlen(fb_name) != 0)
293 }
else if (strcmp(fb_cmd_str,
"isset") == 0) {
295 }
else if (strcmp(fb_cmd_str,
"isnotset") == 0) {
297 }
else if (strcmp(fb_cmd_str,
"set") == 0) {
299 }
else if (strcmp(fb_cmd_str,
"unset") == 0) {
301 }
else if (strcmp(fb_cmd_str,
"toggle") == 0) {
304 SCLogError(
"ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str);
315 if (strlen(fb_name) == 0)
323 if (strchr(fb_name,
'|') != NULL) {
324 int retval = FlowbitOrAddData(
de_ctx, cd, fb_name);
335 SCLogDebug(
"idx %" PRIu32
", cmd %s, name %s",
336 cd->
idx, fb_cmd_str, strlen(fb_name) ? fb_name :
"(none)");
418 struct FBAnalyze *array, uint32_t elements);
427 uint32_t array_size = max_fb_id + 1;
431 SCLogError(
"Unable to allocate flowbit analyze array");
436 (uint64_t)(array_size *
sizeof(
struct FBAnalyze)));
583 for (uint32_t i = 0; i < array_size; i++) {
588 bool to_state =
false;
596 "set. Checked in %u and %u other sigs",
602 SCLogDebug(
"flowbit %s/%u: isset in state, set not in state", varname, i);
611 SCLogDebug(
"flowbit %s/%u: isset not in state, set in state", varname, i);
615 SCLogDebug(
"ALL flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
619 SCLogDebug(
"STATE flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
624 SCLogDebug(
"SET flowbit %s/%u: SID %u", varname, i,
630 SCLogDebug(
"GET flowbit %s/%u: SID %u", varname, i, s->
id);
640 SCCalloc(sids_array_size,
sizeof(uint32_t));
642 SCLogError(
"Failed to allocate memory for rule_state_dependant_ids");
649 SCLogError(
"Failed to allocate memory for rule_state_variable_idx");
653 SCLogDebug(
"alloc'ed array for rule dependency and fbs idx array, sid %u, "
654 "sizes are %u and %u",
658 uint32_t new_array_size =
661 new_array_size *
sizeof(uint32_t));
662 if (tmp_ptr == NULL) {
663 SCLogError(
"Failed to allocate memory for rule_state_variable_idx");
668 SCLogDebug(
"realloc'ed array for rule dependency, sid %u, new size is %u",
672 new_fb_array_size *
sizeof(uint32_t));
675 SCLogError(
"Failed to reallocate memory for rule_state_variable_idx");
679 "realloc'ed array for flowbits ids, new size is %u", new_fb_array_size);
697 SCLogDebug(
"made SID %u stateful because it depends on "
698 "stateful rules that set flowbit %s", s->
id, varname);
704 DetectFlowbitsAnalyzeDump(
de_ctx, array, array_size);
708 for (uint32_t i = 0; i < array_size; i++) {
722 struct FBAnalyze *array, uint32_t elements)
724 JsonBuilder *js = jb_new_object();
728 jb_open_array(js,
"flowbits");
729 for (uint32_t x = 0; x < elements; x++) {
737 jb_set_string(js,
"name", varname);
738 jb_set_uint(js,
"internal_id", x);
747 jb_open_array(js,
"sets");
750 jb_append_uint(js, s->
id);
756 jb_open_array(js,
"isset");
759 jb_append_uint(js, s->
id);
765 jb_open_array(js,
"isnotset");
768 jb_append_uint(js, s->
id);
774 jb_open_array(js,
"unset");
777 jb_append_uint(js, s->
id);
783 jb_open_array(js,
"toggle");
786 jb_append_uint(js, s->
id);
795 const char *filename =
"flowbits.json";
797 char log_path[PATH_MAX] =
"";
798 snprintf(log_path,
sizeof(log_path),
"%s/%s", log_dir, filename);
801 FILE *fp = fopen(log_path,
"w");
803 fwrite(jb_ptr(js), jb_len(js), 1, fp);
814 static int FlowBitsTestParse01(
void)
816 char command[16] =
"",
name[16] =
"";
819 FAIL_IF(!DetectFlowbitParse(
"noalert", command,
sizeof(command),
name,
821 FAIL_IF(strcmp(command,
"noalert") != 0);
824 FAIL_IF(!DetectFlowbitParse(
"set,flowbit", command,
sizeof(command),
name,
826 FAIL_IF(strcmp(command,
"set") != 0);
830 FAIL_IF(!DetectFlowbitParse(
"set, flowbit", command,
sizeof(command),
name,
832 FAIL_IF(strcmp(command,
"set") != 0);
836 FAIL_IF(!DetectFlowbitParse(
"set,flowbit ", command,
sizeof(command),
name,
838 FAIL_IF(strcmp(command,
"set") != 0);
842 FAIL_IF(!DetectFlowbitParse(
"set, flowbit ", command,
sizeof(command),
name,
844 FAIL_IF(strcmp(command,
"set") != 0);
848 FAIL_IF(DetectFlowbitParse(
"set,namewith space", command,
sizeof(command),
861 static int FlowBitsTestSig01(
void)
871 s =
de_ctx->
sig_list =
SigInit(
de_ctx,
"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert,wrongusage; content:\"GET \"; sid:1;)");
886 static int FlowBitsTestSig02(
void)
892 memset(&th_v, 0,
sizeof(th_v));
899 s =
de_ctx->
sig_list =
SigInit(
de_ctx,
"alert ip any any -> any any (msg:\"isset rule need an option\"; flowbits:isset; content:\"GET \"; sid:1;)");
902 s =
de_ctx->
sig_list =
SigInit(
de_ctx,
"alert ip any any -> any any (msg:\"isnotset rule need an option\"; flowbits:isnotset; content:\"GET \"; sid:2;)");
905 s =
de_ctx->
sig_list =
SigInit(
de_ctx,
"alert ip any any -> any any (msg:\"set rule need an option\"; flowbits:set; content:\"GET \"; sid:3;)");
908 s =
de_ctx->
sig_list =
SigInit(
de_ctx,
"alert ip any any -> any any (msg:\"unset rule need an option\"; flowbits:unset; content:\"GET \"; sid:4;)");
911 s =
de_ctx->
sig_list =
SigInit(
de_ctx,
"alert ip any any -> any any (msg:\"toggle rule need an option\"; flowbits:toggle; content:\"GET \"; sid:5;)");
914 s =
de_ctx->
sig_list =
SigInit(
de_ctx,
"alert ip any any -> any any (msg:\"!set is not an option\"; flowbits:!set,myerr; content:\"GET \"; sid:6;)");
930 static int FlowBitsTestSig03(
void)
940 s =
de_ctx->
sig_list =
SigInit(
de_ctx,
"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)");
955 static int FlowBitsTestSig04(
void)
965 s =
de_ctx->
sig_list =
SigInit(
de_ctx,
"alert ip any any -> any any (msg:\"isset option\"; flowbits:isset,fbt; content:\"GET \"; sid:1;)");
983 static int FlowBitsTestSig05(
void)
993 s =
de_ctx->
sig_list =
SigInit(
de_ctx,
"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert; content:\"GET \"; sid:1;)");
1009 static int FlowBitsTestSig06(
void)
1011 uint8_t *buf = (uint8_t *)
1012 "GET /one/ HTTP/1.1\r\n"
1013 "Host: one.example.org\r\n"
1015 uint16_t buflen = strlen((
char *)buf);
1027 memset(&th_v, 0,
sizeof(th_v));
1028 memset(&f, 0,
sizeof(
Flow));
1039 p->
proto = IPPROTO_TCP;
1059 for ( ; gv != NULL; gv = gv->
next) {
1082 static int FlowBitsTestSig07(
void)
1084 uint8_t *buf = (uint8_t *)
1085 "GET /one/ HTTP/1.1\r\n"
1086 "Host: one.example.org\r\n"
1088 uint16_t buflen = strlen((
char *)buf);
1100 memset(&th_v, 0,
sizeof(th_v));
1101 memset(&f, 0,
sizeof(
Flow));
1112 p->
proto = IPPROTO_TCP;
1122 s = s->
next =
SigInit(
de_ctx,
"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)");
1134 for ( ; gv != NULL; gv = gv->
next) {
1157 static int FlowBitsTestSig08(
void)
1159 uint8_t *buf = (uint8_t *)
1160 "GET /one/ HTTP/1.1\r\n"
1161 "Host: one.example.org\r\n"
1163 uint16_t buflen = strlen((
char *)buf);
1176 memset(&th_v, 0,
sizeof(th_v));
1177 memset(&f, 0,
sizeof(
Flow));
1188 p->
proto = IPPROTO_TCP;
1198 s = s->
next =
SigInit(
de_ctx,
"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:toggle,myflow2; sid:11;)");
1210 for ( ; gv != NULL; gv = gv->
next) {
uint16_t cnts[DETECT_FLOWBITS_CMD_MAX]
uint32_t rule_state_dependant_sids_idx
uint32_t isnotset_sids_idx
SCMutex g_flowbits_dump_write_m
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
struct SigMatch_ * smlists[DETECT_SM_LIST_MAX]
#define DETECT_FLOWBITS_CMD_MAX
SigTableElmt * sigmatch_table
void(* Free)(DetectEngineCtx *, void *)
void FlowBitsRegisterTests(void)
this function registers unit tests for FlowBits
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
bool is_rule_state_dependant
struct HtpBodyChunk_ * next
#define DETECT_FLOWBITS_CMD_ISNOTSET
int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx)
main detection engine ctx
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
#define FLOW_PKT_TOSERVER
const char * VarNameStoreSetupLookup(const uint32_t id, const enum VarTypes type)
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
#define SCMUTEX_INITIALIZER
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
#define DETECT_FLOWBITS_CMD_TOGGLE
#define DETECT_FLOWBITS_CMD_ISSET
uint32_t VarNameStoreRegister(const char *name, const enum VarTypes type)
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
void FlowBitUnset(Flow *f, uint32_t idx)
@ DETECT_SM_LIST_POSTMATCH
#define FLOW_INITIALIZE(f)
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
struct GenericVar_ * next
#define PASS
Pass the test.
#define SCMutexUnlock(mut)
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
void FlowBitSet(Flow *f, uint32_t idx)
Per thread variable structure.
uint32_t rule_state_flowbits_ids_size
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
void VarNameStoreUnregister(const uint32_t id, const enum VarTypes type)
#define SCLogWarning(...)
Macro used to log WARNING messages.
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
void DetectFlowbitFree(DetectEngineCtx *, void *)
void DetectFlowbitsRegister(void)
SignatureInitData * init_data
uint32_t * rule_state_dependant_sids_array
Data structures and function prototypes for keeping state for the detection engine.
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
uint32_t rule_state_dependant_sids_size
void FlowBitToggle(Flow *f, uint32_t idx)
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
uint32_t toggle_sids_size
#define SCRealloc(ptr, sz)
#define SIG_FLAG_INIT_STATE_MATCH
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
uint16_t state_cnts[DETECT_FLOWBITS_CMD_MAX]
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
const char * ConfigGetLogDirectory(void)
int FlowBitIsset(Flow *f, uint32_t idx)
#define SCLogError(...)
Macro used to log ERROR messages.
#define DETECT_FLOWBITS_CMD_UNSET
a single match condition for a signature
uint32_t isnotset_sids_size
DetectEngineCtx * DetectEngineCtxInit(void)
int DetectFlowbitMatch(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
SigMatch * SigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
uint32_t * rule_state_flowbits_ids_array
#define SIGMATCH_IPONLY_COMPAT
#define FLOW_PKT_TOSERVER_FIRST
bool rule_engine_analysis_set
int FlowBitIsnotset(Flow *f, uint32_t idx)
#define DETECT_FLOWBITS_CMD_SET
void(* RegisterTests)(void)