suricata
detect-flow-pkts.c
Go to the documentation of this file.
1 /* Copyright (C) 2023-2025 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 #include "suricata-common.h"
19 #include "rust.h"
20 #include "detect-flow-pkts.h"
21 #include "detect-engine.h"
23 #include "detect-engine-uint.h"
24 #include "detect-parse.h"
25 
26 static int DetectFlowPktsMatch(
27  DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx)
28 {
29  if (p->flow == NULL) {
30  return 0;
31  }
32 
33  const DetectFlowPkts *df = (const DetectFlowPkts *)ctx;
34  if (df->dir == DETECT_FLOW_TOSERVER) {
35  return DetectU32Match(p->flow->todstpktcnt, &df->pkt_data);
36  } else if (df->dir == DETECT_FLOW_TOCLIENT) {
37  return DetectU32Match(p->flow->tosrcpktcnt, &df->pkt_data);
38  } else if (df->dir == DETECT_FLOW_TOEITHER) {
39  if (DetectU32Match(p->flow->tosrcpktcnt, &df->pkt_data)) {
40  return 1;
41  }
42  return DetectU32Match(p->flow->todstpktcnt, &df->pkt_data);
43  } else if (df->dir == DETECT_FLOW_TOBOTH) {
44  if (DetectU32Match(p->flow->tosrcpktcnt, &df->pkt_data) &&
45  DetectU32Match(p->flow->todstpktcnt, &df->pkt_data)) {
46  return 1;
47  }
48  }
49  return 0;
50 }
51 
52 static void DetectFlowPktsFree(DetectEngineCtx *de_ctx, void *ptr)
53 {
54  if (ptr != NULL) {
55  SCDetectFlowPktsFree(ptr);
56  }
57 }
58 
59 static int DetectFlowPktsToServerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
60 {
61  DetectFlowPkts *df = SCDetectFlowPktsParseDir(rawstr, DETECT_FLOW_TOSERVER);
62  if (df == NULL) {
63  return -1;
64  }
65 
68  DetectFlowPktsFree(de_ctx, df);
69  return -1;
70  }
72 
73  return 0;
74 }
75 
76 static int DetectFlowPktsToClientSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
77 {
78  DetectFlowPkts *df = SCDetectFlowPktsParseDir(rawstr, DETECT_FLOW_TOCLIENT);
79  if (df == NULL) {
80  return -1;
81  }
84  DetectFlowPktsFree(de_ctx, df);
85  return -1;
86  }
88 
89  return 0;
90 }
91 
92 static int DetectFlowPktsSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
93 {
94  DetectFlowPkts *df = SCDetectFlowPktsParse(rawstr);
95  if (df == NULL) {
96  return -1;
97  }
100  DetectFlowPktsFree(de_ctx, df);
101  return -1;
102  }
103 
105 
106  return 0;
107 }
108 
109 static void PrefilterPacketFlowPktsSet(PrefilterPacketHeaderValue *v, void *smctx)
110 {
111  const DetectFlowPkts *df = smctx;
112  const DetectUintData_u32 *data = &df->pkt_data;
113  v->u8[0] = data->mode;
114  v->u8[1] = (uint8_t)df->dir;
115  v->u32[1] = data->arg1;
116  v->u32[2] = data->arg2;
117 }
118 
119 static bool PrefilterPacketFlowPktsCompare(PrefilterPacketHeaderValue v, void *smctx)
120 {
121  const DetectFlowPkts *df = smctx;
122  return v.u8[0] == df->pkt_data.mode && v.u8[1] == df->dir && v.u32[1] == df->pkt_data.arg1 &&
123  v.u32[2] == df->pkt_data.arg2;
124 }
125 
126 static void PrefilterPacketFlowPktsMatch(
127  DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
128 {
129  const PrefilterPacketHeaderCtx *ctx = pectx;
130  if (!PrefilterPacketHeaderExtraMatch(ctx, p))
131  return;
132 
133  DetectFlowPkts df;
134  DetectUintData_u32 data = {
135  .mode = ctx->v1.u8[0], .arg1 = ctx->v1.u32[1], .arg2 = ctx->v1.u32[2]
136  };
137  df.pkt_data = data;
138  df.dir = ctx->v1.u8[1];
139 
140  if (DetectFlowPktsMatch(det_ctx, p, NULL, (const SigMatchCtx *)&df)) {
141  PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
142  }
143 }
144 
145 static int PrefilterSetupFlowPkts(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
146 {
148  PrefilterPacketFlowPktsSet, PrefilterPacketFlowPktsCompare,
149  PrefilterPacketFlowPktsMatch);
150 }
151 
152 static bool PrefilterFlowPktsIsPrefilterable(const Signature *s)
153 {
154  return PrefilterIsPrefilterableById(s, DETECT_FLOW_PKTS);
155 }
156 
158 {
159  sigmatch_table[DETECT_FLOW_PKTS].name = "flow.pkts";
160  sigmatch_table[DETECT_FLOW_PKTS].desc = "match number of packets in a flow";
161  sigmatch_table[DETECT_FLOW_PKTS].url = "/rules/flow-keywords.html#flow-pkts";
162  sigmatch_table[DETECT_FLOW_PKTS].Match = DetectFlowPktsMatch;
163  sigmatch_table[DETECT_FLOW_PKTS].Setup = DetectFlowPktsSetup;
164  sigmatch_table[DETECT_FLOW_PKTS].Free = DetectFlowPktsFree;
165  sigmatch_table[DETECT_FLOW_PKTS].SupportsPrefilter = PrefilterFlowPktsIsPrefilterable;
166  sigmatch_table[DETECT_FLOW_PKTS].SetupPrefilter = PrefilterSetupFlowPkts;
167 }
168 
170 {
171  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].name = "flow.pkts_toserver";
173  "match number of packets in a flow in to server direction";
174  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].url = "/rules/flow-keywords.html#flow-pkts";
175  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].Match = DetectFlowPktsMatch;
176  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].Setup = DetectFlowPktsToServerSetup;
177  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].Free = DetectFlowPktsFree;
179  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].SupportsPrefilter = PrefilterFlowPktsIsPrefilterable;
180  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].SetupPrefilter = PrefilterSetupFlowPkts;
181 }
182 
184 {
185  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].name = "flow.pkts_toclient";
187  "match number of packets in a flow in to client direction";
188  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].url = "/rules/flow-keywords.html#flow-pkts";
189  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].Match = DetectFlowPktsMatch;
190  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].Setup = DetectFlowPktsToClientSetup;
191  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].Free = DetectFlowPktsFree;
193  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].SupportsPrefilter = PrefilterFlowPktsIsPrefilterable;
194  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].SetupPrefilter = PrefilterSetupFlowPkts;
195 }
196 
197 static int DetectFlowBytesMatch(
198  DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx)
199 {
200  if (p->flow == NULL) {
201  return 0;
202  }
203 
204  const DetectFlowBytes *df = (const DetectFlowBytes *)ctx;
205  if (df->dir == DETECT_FLOW_TOSERVER) {
206  return DetectU64Match(p->flow->todstbytecnt, &df->byte_data);
207  } else if (df->dir == DETECT_FLOW_TOCLIENT) {
208  return DetectU64Match(p->flow->tosrcbytecnt, &df->byte_data);
209  } else if (df->dir == DETECT_FLOW_TOEITHER) {
210  if (DetectU64Match(p->flow->tosrcbytecnt, &df->byte_data)) {
211  return 1;
212  }
213  return DetectU64Match(p->flow->todstbytecnt, &df->byte_data);
214  } else if (df->dir == DETECT_FLOW_TOBOTH) {
215  if (DetectU64Match(p->flow->tosrcbytecnt, &df->byte_data) &&
216  DetectU64Match(p->flow->todstbytecnt, &df->byte_data)) {
217  return 1;
218  }
219  }
220  return 0;
221 }
222 
223 static void DetectFlowBytesFree(DetectEngineCtx *de_ctx, void *ptr)
224 {
225  if (ptr != NULL) {
226  SCDetectFlowBytesFree(ptr);
227  }
228 }
229 
230 static int DetectFlowBytesToServerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
231 {
232  DetectFlowBytes *df = SCDetectFlowBytesParseDir(rawstr, DETECT_FLOW_TOSERVER);
233  if (df == NULL) {
234  return -1;
235  }
236 
239  DetectFlowBytesFree(de_ctx, df);
240  return -1;
241  }
243 
244  return 0;
245 }
246 
247 static int DetectFlowBytesToClientSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
248 {
249  DetectFlowBytes *df = SCDetectFlowBytesParseDir(rawstr, DETECT_FLOW_TOCLIENT);
250  if (df == NULL) {
251  return -1;
252  }
253 
256  DetectFlowBytesFree(de_ctx, df);
257  return -1;
258  }
260 
261  return 0;
262 }
263 
264 static int DetectFlowBytesSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
265 {
266  DetectFlowBytes *df = SCDetectFlowBytesParse(rawstr);
267  if (df == NULL) {
268  return -1;
269  }
272  DetectFlowBytesFree(de_ctx, df);
273  return -1;
274  }
276 
277  return 0;
278 }
279 
281 {
282  sigmatch_table[DETECT_FLOW_BYTES].name = "flow.bytes";
283  sigmatch_table[DETECT_FLOW_BYTES].desc = "match number of bytes in a flow";
284  sigmatch_table[DETECT_FLOW_BYTES].url = "/rules/flow-keywords.html#flow-bytes";
285  sigmatch_table[DETECT_FLOW_BYTES].Match = DetectFlowBytesMatch;
286  sigmatch_table[DETECT_FLOW_BYTES].Setup = DetectFlowBytesSetup;
287  sigmatch_table[DETECT_FLOW_BYTES].Free = DetectFlowBytesFree;
288 }
289 
291 {
292  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].name = "flow.bytes_toserver";
294  "match number of bytes in a flow in to server dir";
295  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].url = "/rules/flow-keywords.html#flow-bytes";
296  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].Match = DetectFlowBytesMatch;
297  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].Setup = DetectFlowBytesToServerSetup;
298  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].Free = DetectFlowBytesFree;
300 }
301 
303 {
304  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].name = "flow.bytes_toclient";
306  "match number of bytes in a flow in to client dir";
307  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].url = "/rules/flow-keywords.html#flow-bytes";
308  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].Match = DetectFlowBytesMatch;
309  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].Setup = DetectFlowBytesToClientSetup;
310  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].Free = DetectFlowBytesFree;
312 }
detect-engine-uint.h
SigTableElmt_::url
const char * url
Definition: detect.h:1471
DetectFlowBytesRegister
void DetectFlowBytesRegister(void)
Definition: detect-flow-pkts.c:280
detect-engine.h
DetectU32Match
int DetectU32Match(const uint32_t parg, const DetectUintData_u32 *du32)
Definition: detect-engine-uint.c:31
SigTableElmt_::desc
const char * desc
Definition: detect.h:1470
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:79
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1455
SigTableElmt_::name
const char * name
Definition: detect.h:1468
SigGroupHead_
Container for matching data for a signature group.
Definition: detect.h:1638
SigTableElmt_::flags
uint32_t flags
Definition: detect.h:1459
DetectEngineThreadCtx_::pmq
PrefilterRuleStore pmq
Definition: detect.h:1358
ctx
struct Thresholds ctx
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:937
PrefilterPacketHeaderValue::u8
uint8_t u8[16]
Definition: detect-engine-prefilter-common.h:24
rust.h
DetectFlowBytesToClientRegister
void DetectFlowBytesToClientRegister(void)
Definition: detect-flow-pkts.c:302
DETECT_FLOW_BYTES
@ DETECT_FLOW_BYTES
Definition: detect-engine-register.h:135
DetectFlowBytesToServerRegister
void DetectFlowBytesToServerRegister(void)
Definition: detect-flow-pkts.c:290
DetectFlowPktsRegister
void DetectFlowPktsRegister(void)
Definition: detect-flow-pkts.c:157
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1450
detect-engine-prefilter.h
SigTableElmt_::SetupPrefilter
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition: detect.h:1453
DETECT_FLOW_BYTES_TO_SERVER
@ DETECT_FLOW_BYTES_TO_SERVER
Definition: detect-engine-register.h:136
Flow_::tosrcbytecnt
uint64_t tosrcbytecnt
Definition: flow.h:491
DetectFlowPktsToClientRegister
void DetectFlowPktsToClientRegister(void)
Definition: detect-flow-pkts.c:183
PrefilterPacketHeaderCtx_
Definition: detect-engine-prefilter-common.h:35
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:19
DetectEngineThreadCtx_
Definition: detect.h:1252
Flow_::todstpktcnt
uint32_t todstpktcnt
Definition: flow.h:488
SIG_MASK_REQUIRE_FLOW
#define SIG_MASK_REQUIRE_FLOW
Definition: detect.h:312
PrefilterPacketHeaderValue::u32
uint32_t u32[4]
Definition: detect-engine-prefilter-common.h:26
SCSigMatchAppendSMToList
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:387
SIGMATCH_INFO_UINT64
#define SIGMATCH_INFO_UINT64
Definition: detect-engine-register.h:351
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:117
DETECT_FLOW_BYTES_TO_CLIENT
@ DETECT_FLOW_BYTES_TO_CLIENT
Definition: detect-engine-register.h:137
Flow_::todstbytecnt
uint64_t todstbytecnt
Definition: flow.h:490
DetectFlowPktsToServerRegister
void DetectFlowPktsToServerRegister(void)
Definition: detect-flow-pkts.c:169
Signature_::flags
uint32_t flags
Definition: detect.h:673
Packet_
Definition: decode.h:505
PrefilterSetupPacketHeader
int PrefilterSetupPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, SignatureMask mask, void(*Set)(PrefilterPacketHeaderValue *v, void *), bool(*Compare)(PrefilterPacketHeaderValue v, void *), void(*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
Definition: detect-engine-prefilter-common.c:470
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1430
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:351
Packet_::flow
struct Flow_ * flow
Definition: decode.h:553
suricata-common.h
DETECT_FLOW_PKTS_TO_SERVER
@ DETECT_FLOW_PKTS_TO_SERVER
Definition: detect-engine-register.h:133
SigTableElmt_::SupportsPrefilter
bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1452
SIGMATCH_INFO_UINT32
#define SIGMATCH_INFO_UINT32
Definition: detect-engine-register.h:349
detect-parse.h
Signature_
Signature container.
Definition: detect.h:672
DetectU64Match
int DetectU64Match(const uint64_t parg, const DetectUintData_u64 *du64)
Definition: detect-engine-uint.c:138
detect-flow-pkts.h
PrefilterPacketHeaderValue
Definition: detect-engine-prefilter-common.h:23
DETECT_FLOW_PKTS_TO_CLIENT
@ DETECT_FLOW_PKTS_TO_CLIENT
Definition: detect-engine-register.h:134
DETECT_FLOW_PKTS
@ DETECT_FLOW_PKTS
Definition: detect-engine-register.h:132
Flow_::tosrcpktcnt
uint32_t tosrcpktcnt
Definition: flow.h:489
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:253