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  if (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  return true;
125  }
126  return false;
127 }
128 
129 static void PrefilterPacketFlowPktsMatch(
130  DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
131 {
132  const PrefilterPacketHeaderCtx *ctx = pectx;
133  if (!PrefilterPacketHeaderExtraMatch(ctx, p))
134  return;
135 
136  DetectFlowPkts df;
137  DetectUintData_u32 data = {
138  .mode = ctx->v1.u8[0], .arg1 = ctx->v1.u32[1], .arg2 = ctx->v1.u32[2]
139  };
140  df.pkt_data = data;
141  df.dir = ctx->v1.u8[1];
142 
143  if (DetectFlowPktsMatch(det_ctx, p, NULL, (const SigMatchCtx *)&df)) {
144  PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
145  }
146 }
147 
148 static int PrefilterSetupFlowPkts(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
149 {
151  PrefilterPacketFlowPktsSet, PrefilterPacketFlowPktsCompare,
152  PrefilterPacketFlowPktsMatch);
153 }
154 
155 static bool PrefilterFlowPktsIsPrefilterable(const Signature *s)
156 {
157  return PrefilterIsPrefilterableById(s, DETECT_FLOW_PKTS);
158 }
159 
161 {
162  sigmatch_table[DETECT_FLOW_PKTS].name = "flow.pkts";
163  sigmatch_table[DETECT_FLOW_PKTS].desc = "match number of packets in a flow";
164  sigmatch_table[DETECT_FLOW_PKTS].url = "/rules/flow-keywords.html#flow-pkts";
165  sigmatch_table[DETECT_FLOW_PKTS].Match = DetectFlowPktsMatch;
166  sigmatch_table[DETECT_FLOW_PKTS].Setup = DetectFlowPktsSetup;
167  sigmatch_table[DETECT_FLOW_PKTS].Free = DetectFlowPktsFree;
168  sigmatch_table[DETECT_FLOW_PKTS].SupportsPrefilter = PrefilterFlowPktsIsPrefilterable;
169  sigmatch_table[DETECT_FLOW_PKTS].SetupPrefilter = PrefilterSetupFlowPkts;
170 }
171 
173 {
174  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].name = "flow.pkts_toserver";
176  "match number of packets in a flow in to server direction";
177  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].url = "/rules/flow-keywords.html#flow-pkts";
178  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].Match = DetectFlowPktsMatch;
179  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].Setup = DetectFlowPktsToServerSetup;
180  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].Free = DetectFlowPktsFree;
182  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].SupportsPrefilter = PrefilterFlowPktsIsPrefilterable;
183  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].SetupPrefilter = PrefilterSetupFlowPkts;
184 }
185 
187 {
188  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].name = "flow.pkts_toclient";
190  "match number of packets in a flow in to client direction";
191  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].url = "/rules/flow-keywords.html#flow-pkts";
192  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].Match = DetectFlowPktsMatch;
193  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].Setup = DetectFlowPktsToClientSetup;
194  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].Free = DetectFlowPktsFree;
196  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].SupportsPrefilter = PrefilterFlowPktsIsPrefilterable;
197  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].SetupPrefilter = PrefilterSetupFlowPkts;
198 }
199 
200 static int DetectFlowBytesMatch(
201  DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx)
202 {
203  if (p->flow == NULL) {
204  return 0;
205  }
206 
207  const DetectFlowBytes *df = (const DetectFlowBytes *)ctx;
208  if (df->dir == DETECT_FLOW_TOSERVER) {
209  return DetectU64Match(p->flow->todstbytecnt, &df->byte_data);
210  } else if (df->dir == DETECT_FLOW_TOCLIENT) {
211  return DetectU64Match(p->flow->tosrcbytecnt, &df->byte_data);
212  } else if (df->dir == DETECT_FLOW_TOEITHER) {
213  if (DetectU64Match(p->flow->tosrcbytecnt, &df->byte_data)) {
214  return 1;
215  }
216  return DetectU64Match(p->flow->todstbytecnt, &df->byte_data);
217  } else if (df->dir == DETECT_FLOW_TOBOTH) {
218  if (DetectU64Match(p->flow->tosrcbytecnt, &df->byte_data) &&
219  DetectU64Match(p->flow->todstbytecnt, &df->byte_data)) {
220  return 1;
221  }
222  }
223  return 0;
224 }
225 
226 static void DetectFlowBytesFree(DetectEngineCtx *de_ctx, void *ptr)
227 {
228  if (ptr != NULL) {
229  SCDetectFlowBytesFree(ptr);
230  }
231 }
232 
233 static int DetectFlowBytesToServerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
234 {
235  DetectFlowBytes *df = SCDetectFlowBytesParseDir(rawstr, DETECT_FLOW_TOSERVER);
236  if (df == NULL) {
237  return -1;
238  }
239 
242  DetectFlowBytesFree(de_ctx, df);
243  return -1;
244  }
246 
247  return 0;
248 }
249 
250 static int DetectFlowBytesToClientSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
251 {
252  DetectFlowBytes *df = SCDetectFlowBytesParseDir(rawstr, DETECT_FLOW_TOCLIENT);
253  if (df == NULL) {
254  return -1;
255  }
256 
259  DetectFlowBytesFree(de_ctx, df);
260  return -1;
261  }
263 
264  return 0;
265 }
266 
267 static int DetectFlowBytesSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
268 {
269  DetectFlowBytes *df = SCDetectFlowBytesParse(rawstr);
270  if (df == NULL) {
271  return -1;
272  }
275  DetectFlowBytesFree(de_ctx, df);
276  return -1;
277  }
279 
280  return 0;
281 }
282 
284 {
285  sigmatch_table[DETECT_FLOW_BYTES].name = "flow.bytes";
286  sigmatch_table[DETECT_FLOW_BYTES].desc = "match number of bytes in a flow";
287  sigmatch_table[DETECT_FLOW_BYTES].url = "/rules/flow-keywords.html#flow-bytes";
288  sigmatch_table[DETECT_FLOW_BYTES].Match = DetectFlowBytesMatch;
289  sigmatch_table[DETECT_FLOW_BYTES].Setup = DetectFlowBytesSetup;
290  sigmatch_table[DETECT_FLOW_BYTES].Free = DetectFlowBytesFree;
291 }
292 
294 {
295  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].name = "flow.bytes_toserver";
297  "match number of bytes in a flow in to server dir";
298  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].url = "/rules/flow-keywords.html#flow-bytes";
299  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].Match = DetectFlowBytesMatch;
300  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].Setup = DetectFlowBytesToServerSetup;
301  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].Free = DetectFlowBytesFree;
303 }
304 
306 {
307  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].name = "flow.bytes_toclient";
309  "match number of bytes in a flow in to client dir";
310  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].url = "/rules/flow-keywords.html#flow-bytes";
311  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].Match = DetectFlowBytesMatch;
312  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].Setup = DetectFlowBytesToClientSetup;
313  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].Free = DetectFlowBytesFree;
315 }
detect-engine-uint.h
SigTableElmt_::url
const char * url
Definition: detect.h:1461
DetectFlowBytesRegister
void DetectFlowBytesRegister(void)
Definition: detect-flow-pkts.c:283
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:1460
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:79
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1445
SigTableElmt_::name
const char * name
Definition: detect.h:1458
SigGroupHead_
Container for matching data for a signature group.
Definition: detect.h:1628
SigTableElmt_::flags
uint32_t flags
Definition: detect.h:1449
DetectEngineThreadCtx_::pmq
PrefilterRuleStore pmq
Definition: detect.h:1348
ctx
struct Thresholds ctx
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:933
PrefilterPacketHeaderValue::u8
uint8_t u8[16]
Definition: detect-engine-prefilter-common.h:24
rust.h
DetectFlowBytesToClientRegister
void DetectFlowBytesToClientRegister(void)
Definition: detect-flow-pkts.c:305
DETECT_FLOW_BYTES
@ DETECT_FLOW_BYTES
Definition: detect-engine-register.h:132
DetectFlowBytesToServerRegister
void DetectFlowBytesToServerRegister(void)
Definition: detect-flow-pkts.c:293
DetectFlowPktsRegister
void DetectFlowPktsRegister(void)
Definition: detect-flow-pkts.c:160
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1440
detect-engine-prefilter.h
SigTableElmt_::SetupPrefilter
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition: detect.h:1443
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:1691
Flow_::tosrcbytecnt
uint64_t tosrcbytecnt
Definition: flow.h:489
DetectFlowPktsToClientRegister
void DetectFlowPktsToClientRegister(void)
Definition: detect-flow-pkts.c:186
PrefilterPacketHeaderCtx_
Definition: detect-engine-prefilter-common.h:35
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:19
DetectEngineThreadCtx_
Definition: detect.h:1245
Flow_::todstpktcnt
uint32_t todstpktcnt
Definition: flow.h:486
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:488
DetectFlowPktsToServerRegister
void DetectFlowPktsToServerRegister(void)
Definition: detect-flow-pkts.c:172
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:1420
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:1693
SigTableElmt_::SupportsPrefilter
bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1442
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:487
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:254