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  }
44  return 0;
45 }
46 
47 static void DetectFlowPktsFree(DetectEngineCtx *de_ctx, void *ptr)
48 {
49  if (ptr != NULL) {
50  SCDetectFlowPktsFree(ptr);
51  }
52 }
53 
54 static int DetectFlowPktsToServerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
55 {
56  DetectFlowPkts *df = SCDetectFlowPktsParseDir(rawstr, DETECT_FLOW_TOSERVER);
57  if (df == NULL) {
58  return -1;
59  }
60 
63  DetectFlowPktsFree(de_ctx, df);
64  return -1;
65  }
67 
68  return 0;
69 }
70 
71 static int DetectFlowPktsToClientSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
72 {
73  DetectFlowPkts *df = SCDetectFlowPktsParseDir(rawstr, DETECT_FLOW_TOCLIENT);
74  if (df == NULL) {
75  return -1;
76  }
79  DetectFlowPktsFree(de_ctx, df);
80  return -1;
81  }
83 
84  return 0;
85 }
86 
87 static int DetectFlowPktsSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
88 {
89  DetectFlowPkts *df = SCDetectFlowPktsParse(rawstr);
90  if (df == NULL) {
91  return -1;
92  }
95  DetectFlowPktsFree(de_ctx, df);
96  return -1;
97  }
98 
100 
101  return 0;
102 }
103 
104 static void PrefilterPacketFlowPktsSet(PrefilterPacketHeaderValue *v, void *smctx)
105 {
106  const DetectFlowPkts *df = smctx;
107  const DetectUintData_u32 *data = &df->pkt_data;
108  v->u8[0] = data->mode;
109  v->u8[1] = (uint8_t)df->dir;
110  v->u32[1] = data->arg1;
111  v->u32[2] = data->arg2;
112 }
113 
114 static bool PrefilterPacketFlowPktsCompare(PrefilterPacketHeaderValue v, void *smctx)
115 {
116  const DetectFlowPkts *df = smctx;
117  if (v.u8[0] == df->pkt_data.mode && v.u8[1] == df->dir && v.u32[1] == df->pkt_data.arg1 &&
118  v.u32[2] == df->pkt_data.arg2) {
119  return true;
120  }
121  return false;
122 }
123 
124 static void PrefilterPacketFlowPktsMatch(
125  DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
126 {
127  const PrefilterPacketHeaderCtx *ctx = pectx;
128  if (!PrefilterPacketHeaderExtraMatch(ctx, p))
129  return;
130 
131  DetectFlowPkts df;
132  DetectUintData_u32 data = {
133  .mode = ctx->v1.u8[0], .arg1 = ctx->v1.u32[1], .arg2 = ctx->v1.u32[2]
134  };
135  df.pkt_data = data;
136  df.dir = ctx->v1.u8[1];
137 
138  if (DetectFlowPktsMatch(det_ctx, p, NULL, (const SigMatchCtx *)&df)) {
139  PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
140  }
141 }
142 
143 static int PrefilterSetupFlowPkts(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
144 {
146  PrefilterPacketFlowPktsSet, PrefilterPacketFlowPktsCompare,
147  PrefilterPacketFlowPktsMatch);
148 }
149 
150 static bool PrefilterFlowPktsIsPrefilterable(const Signature *s)
151 {
152  return PrefilterIsPrefilterableById(s, DETECT_FLOW_PKTS);
153 }
154 
156 {
157  sigmatch_table[DETECT_FLOW_PKTS].name = "flow.pkts";
158  sigmatch_table[DETECT_FLOW_PKTS].desc = "match number of packets in a flow";
159  sigmatch_table[DETECT_FLOW_PKTS].url = "/rules/flow-keywords.html#flow-pkts";
160  sigmatch_table[DETECT_FLOW_PKTS].Match = DetectFlowPktsMatch;
161  sigmatch_table[DETECT_FLOW_PKTS].Setup = DetectFlowPktsSetup;
162  sigmatch_table[DETECT_FLOW_PKTS].Free = DetectFlowPktsFree;
163  sigmatch_table[DETECT_FLOW_PKTS].SupportsPrefilter = PrefilterFlowPktsIsPrefilterable;
164  sigmatch_table[DETECT_FLOW_PKTS].SetupPrefilter = PrefilterSetupFlowPkts;
165 }
166 
168 {
169  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].name = "flow.pkts_toserver";
171  "match number of packets in a flow in to server direction";
172  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].url = "/rules/flow-keywords.html#flow-pkts";
173  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].Match = DetectFlowPktsMatch;
174  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].Setup = DetectFlowPktsToServerSetup;
175  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].Free = DetectFlowPktsFree;
177  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].SupportsPrefilter = PrefilterFlowPktsIsPrefilterable;
178  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].SetupPrefilter = PrefilterSetupFlowPkts;
179 }
180 
182 {
183  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].name = "flow.pkts_toclient";
185  "match number of packets in a flow in to client direction";
186  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].url = "/rules/flow-keywords.html#flow-pkts";
187  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].Match = DetectFlowPktsMatch;
188  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].Setup = DetectFlowPktsToClientSetup;
189  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].Free = DetectFlowPktsFree;
191  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].SupportsPrefilter = PrefilterFlowPktsIsPrefilterable;
192  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].SetupPrefilter = PrefilterSetupFlowPkts;
193 }
194 
195 static int DetectFlowBytesMatch(
196  DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx)
197 {
198  if (p->flow == NULL) {
199  return 0;
200  }
201 
202  const DetectFlowBytes *df = (const DetectFlowBytes *)ctx;
203  if (df->dir == DETECT_FLOW_TOSERVER) {
204  return DetectU64Match(p->flow->todstbytecnt, &df->byte_data);
205  } else if (df->dir == DETECT_FLOW_TOCLIENT) {
206  return DetectU64Match(p->flow->tosrcbytecnt, &df->byte_data);
207  } else if (df->dir == DETECT_FLOW_TOEITHER) {
208  if (DetectU64Match(p->flow->tosrcbytecnt, &df->byte_data)) {
209  return 1;
210  }
211  return DetectU64Match(p->flow->todstbytecnt, &df->byte_data);
212  }
213  return 0;
214 }
215 
216 static void DetectFlowBytesFree(DetectEngineCtx *de_ctx, void *ptr)
217 {
218  if (ptr != NULL) {
219  SCDetectFlowBytesFree(ptr);
220  }
221 }
222 
223 static int DetectFlowBytesToServerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
224 {
225  DetectFlowBytes *df = SCDetectFlowBytesParseDir(rawstr, DETECT_FLOW_TOSERVER);
226  if (df == NULL) {
227  return -1;
228  }
229 
232  DetectFlowBytesFree(de_ctx, df);
233  return -1;
234  }
236 
237  return 0;
238 }
239 
240 static int DetectFlowBytesToClientSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
241 {
242  DetectFlowBytes *df = SCDetectFlowBytesParseDir(rawstr, DETECT_FLOW_TOCLIENT);
243  if (df == NULL) {
244  return -1;
245  }
246 
249  DetectFlowBytesFree(de_ctx, df);
250  return -1;
251  }
253 
254  return 0;
255 }
256 
257 static int DetectFlowBytesSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
258 {
259  DetectFlowBytes *df = SCDetectFlowBytesParse(rawstr);
260  if (df == NULL) {
261  return -1;
262  }
265  DetectFlowBytesFree(de_ctx, df);
266  return -1;
267  }
269 
270  return 0;
271 }
272 
274 {
275  sigmatch_table[DETECT_FLOW_BYTES].name = "flow.bytes";
276  sigmatch_table[DETECT_FLOW_BYTES].desc = "match number of bytes in a flow";
277  sigmatch_table[DETECT_FLOW_BYTES].url = "/rules/flow-keywords.html#flow-bytes";
278  sigmatch_table[DETECT_FLOW_BYTES].Match = DetectFlowBytesMatch;
279  sigmatch_table[DETECT_FLOW_BYTES].Setup = DetectFlowBytesSetup;
280  sigmatch_table[DETECT_FLOW_BYTES].Free = DetectFlowBytesFree;
281 }
282 
284 {
285  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].name = "flow.bytes_toserver";
287  "match number of bytes in a flow in to server dir";
288  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].url = "/rules/flow-keywords.html#flow-bytes";
289  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].Match = DetectFlowBytesMatch;
290  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].Setup = DetectFlowBytesToServerSetup;
291  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].Free = DetectFlowBytesFree;
293 }
294 
296 {
297  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].name = "flow.bytes_toclient";
299  "match number of bytes in a flow in to client dir";
300  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].url = "/rules/flow-keywords.html#flow-bytes";
301  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].Match = DetectFlowBytesMatch;
302  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].Setup = DetectFlowBytesToClientSetup;
303  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].Free = DetectFlowBytesFree;
305 }
detect-engine-uint.h
SigTableElmt_::url
const char * url
Definition: detect.h:1460
DetectFlowBytesRegister
void DetectFlowBytesRegister(void)
Definition: detect-flow-pkts.c:273
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:1459
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:79
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1444
SigTableElmt_::name
const char * name
Definition: detect.h:1457
SigGroupHead_
Container for matching data for a signature group.
Definition: detect.h:1627
SigTableElmt_::flags
uint32_t flags
Definition: detect.h:1448
DetectEngineThreadCtx_::pmq
PrefilterRuleStore pmq
Definition: detect.h:1347
ctx
struct Thresholds ctx
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:932
PrefilterPacketHeaderValue::u8
uint8_t u8[16]
Definition: detect-engine-prefilter-common.h:24
rust.h
DetectFlowBytesToClientRegister
void DetectFlowBytesToClientRegister(void)
Definition: detect-flow-pkts.c:295
DETECT_FLOW_BYTES
@ DETECT_FLOW_BYTES
Definition: detect-engine-register.h:132
DetectFlowBytesToServerRegister
void DetectFlowBytesToServerRegister(void)
Definition: detect-flow-pkts.c:283
DetectFlowPktsRegister
void DetectFlowPktsRegister(void)
Definition: detect-flow-pkts.c:155
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1439
detect-engine-prefilter.h
SigTableElmt_::SetupPrefilter
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition: detect.h:1442
DETECT_FLOW_BYTES_TO_SERVER
@ DETECT_FLOW_BYTES_TO_SERVER
Definition: detect-engine-register.h:133
SIGMATCH_INFO_UINT32
#define SIGMATCH_INFO_UINT32
Definition: detect.h:1690
Flow_::tosrcbytecnt
uint64_t tosrcbytecnt
Definition: flow.h:490
DetectFlowPktsToClientRegister
void DetectFlowPktsToClientRegister(void)
Definition: detect-flow-pkts.c:181
PrefilterPacketHeaderCtx_
Definition: detect-engine-prefilter-common.h:35
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
DetectEngineThreadCtx_
Definition: detect.h:1244
Flow_::todstpktcnt
uint32_t todstpktcnt
Definition: flow.h:487
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:388
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:134
Flow_::todstbytecnt
uint64_t todstbytecnt
Definition: flow.h:489
DetectFlowPktsToServerRegister
void DetectFlowPktsToServerRegister(void)
Definition: detect-flow-pkts.c:167
Signature_::flags
uint32_t flags
Definition: detect.h:669
Packet_
Definition: decode.h:501
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:1419
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:546
suricata-common.h
DETECT_FLOW_PKTS_TO_SERVER
@ DETECT_FLOW_PKTS_TO_SERVER
Definition: detect-engine-register.h:130
SIGMATCH_INFO_UINT64
#define SIGMATCH_INFO_UINT64
Definition: detect.h:1692
SigTableElmt_::SupportsPrefilter
bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1441
detect-parse.h
Signature_
Signature container.
Definition: detect.h:668
DetectU64Match
int DetectU64Match(const uint64_t parg, const DetectUintData_u64 *du64)
Definition: detect-engine-uint.c:142
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:131
DETECT_FLOW_PKTS
@ DETECT_FLOW_PKTS
Definition: detect-engine-register.h:129
Flow_::tosrcpktcnt
uint32_t tosrcpktcnt
Definition: flow.h:488
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:254