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;
176  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].SupportsPrefilter = PrefilterFlowPktsIsPrefilterable;
177  sigmatch_table[DETECT_FLOW_PKTS_TO_SERVER].SetupPrefilter = PrefilterSetupFlowPkts;
178 }
179 
181 {
182  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].name = "flow.pkts_toclient";
184  "match number of packets in a flow in to client direction";
185  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].url = "/rules/flow-keywords.html#flow-pkts";
186  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].Match = DetectFlowPktsMatch;
187  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].Setup = DetectFlowPktsToClientSetup;
188  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].Free = DetectFlowPktsFree;
189  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].SupportsPrefilter = PrefilterFlowPktsIsPrefilterable;
190  sigmatch_table[DETECT_FLOW_PKTS_TO_CLIENT].SetupPrefilter = PrefilterSetupFlowPkts;
191 }
192 
193 static int DetectFlowBytesMatch(
194  DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx)
195 {
196  if (p->flow == NULL) {
197  return 0;
198  }
199 
200  const DetectFlowBytes *df = (const DetectFlowBytes *)ctx;
201  if (df->dir == DETECT_FLOW_TOSERVER) {
202  return DetectU64Match(p->flow->todstbytecnt, &df->byte_data);
203  } else if (df->dir == DETECT_FLOW_TOCLIENT) {
204  return DetectU64Match(p->flow->tosrcbytecnt, &df->byte_data);
205  } else if (df->dir == DETECT_FLOW_TOEITHER) {
206  if (DetectU64Match(p->flow->tosrcbytecnt, &df->byte_data)) {
207  return 1;
208  }
209  return DetectU64Match(p->flow->todstbytecnt, &df->byte_data);
210  }
211  return 0;
212 }
213 
214 static void DetectFlowBytesFree(DetectEngineCtx *de_ctx, void *ptr)
215 {
216  if (ptr != NULL) {
217  SCDetectFlowBytesFree(ptr);
218  }
219 }
220 
221 static int DetectFlowBytesToServerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
222 {
223  DetectFlowBytes *df = SCDetectFlowBytesParseDir(rawstr, DETECT_FLOW_TOSERVER);
224  if (df == NULL) {
225  return -1;
226  }
227 
230  DetectFlowBytesFree(de_ctx, df);
231  return -1;
232  }
234 
235  return 0;
236 }
237 
238 static int DetectFlowBytesToClientSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
239 {
240  DetectFlowBytes *df = SCDetectFlowBytesParseDir(rawstr, DETECT_FLOW_TOCLIENT);
241  if (df == NULL) {
242  return -1;
243  }
244 
247  DetectFlowBytesFree(de_ctx, df);
248  return -1;
249  }
251 
252  return 0;
253 }
254 
255 static int DetectFlowBytesSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
256 {
257  DetectFlowBytes *df = SCDetectFlowBytesParse(rawstr);
258  if (df == NULL) {
259  return -1;
260  }
263  DetectFlowBytesFree(de_ctx, df);
264  return -1;
265  }
267 
268  return 0;
269 }
270 
272 {
273  sigmatch_table[DETECT_FLOW_BYTES].name = "flow.bytes";
274  sigmatch_table[DETECT_FLOW_BYTES].desc = "match number of bytes in a flow";
275  sigmatch_table[DETECT_FLOW_BYTES].url = "/rules/flow-keywords.html#flow-bytes";
276  sigmatch_table[DETECT_FLOW_BYTES].Match = DetectFlowBytesMatch;
277  sigmatch_table[DETECT_FLOW_BYTES].Setup = DetectFlowBytesSetup;
278  sigmatch_table[DETECT_FLOW_BYTES].Free = DetectFlowBytesFree;
279 }
280 
282 {
283  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].name = "flow.bytes_toserver";
285  "match number of bytes in a flow in to server dir";
286  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].url = "/rules/flow-keywords.html#flow-bytes";
287  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].Match = DetectFlowBytesMatch;
288  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].Setup = DetectFlowBytesToServerSetup;
289  sigmatch_table[DETECT_FLOW_BYTES_TO_SERVER].Free = DetectFlowBytesFree;
290 }
291 
293 {
294  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].name = "flow.bytes_toclient";
296  "match number of bytes in a flow in to client dir";
297  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].url = "/rules/flow-keywords.html#flow-bytes";
298  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].Match = DetectFlowBytesMatch;
299  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].Setup = DetectFlowBytesToClientSetup;
300  sigmatch_table[DETECT_FLOW_BYTES_TO_CLIENT].Free = DetectFlowBytesFree;
301 }
detect-engine-uint.h
SigTableElmt_::url
const char * url
Definition: detect.h:1322
DetectFlowBytesRegister
void DetectFlowBytesRegister(void)
Definition: detect-flow-pkts.c:271
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:1321
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:153
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1309
SigTableElmt_::name
const char * name
Definition: detect.h:1319
SigGroupHead_
Container for matching data for a signature group.
Definition: detect.h:1475
DetectEngineThreadCtx_::pmq
PrefilterRuleStore pmq
Definition: detect.h:1215
ctx
struct Thresholds ctx
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:854
PrefilterPacketHeaderValue::u8
uint8_t u8[16]
Definition: detect-engine-prefilter-common.h:24
rust.h
DetectFlowBytesToClientRegister
void DetectFlowBytesToClientRegister(void)
Definition: detect-flow-pkts.c:292
DETECT_FLOW_BYTES
@ DETECT_FLOW_BYTES
Definition: detect-engine-register.h:133
DetectFlowBytesToServerRegister
void DetectFlowBytesToServerRegister(void)
Definition: detect-flow-pkts.c:281
DetectFlowPktsRegister
void DetectFlowPktsRegister(void)
Definition: detect-flow-pkts.c:155
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1304
detect-engine-prefilter.h
SigTableElmt_::SetupPrefilter
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition: detect.h:1307
DETECT_FLOW_BYTES_TO_SERVER
@ DETECT_FLOW_BYTES_TO_SERVER
Definition: detect-engine-register.h:134
Flow_::tosrcbytecnt
uint64_t tosrcbytecnt
Definition: flow.h:493
DetectFlowPktsToClientRegister
void DetectFlowPktsToClientRegister(void)
Definition: detect-flow-pkts.c:180
PrefilterPacketHeaderCtx_
Definition: detect-engine-prefilter-common.h:35
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
DetectEngineThreadCtx_
Definition: detect.h:1109
Flow_::todstpktcnt
uint32_t todstpktcnt
Definition: flow.h:490
SIG_MASK_REQUIRE_FLOW
#define SIG_MASK_REQUIRE_FLOW
Definition: detect.h:304
PrefilterPacketHeaderValue::u32
uint32_t u32[4]
Definition: detect-engine-prefilter-common.h:26
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:116
DETECT_FLOW_BYTES_TO_CLIENT
@ DETECT_FLOW_BYTES_TO_CLIENT
Definition: detect-engine-register.h:135
Flow_::todstbytecnt
uint64_t todstbytecnt
Definition: flow.h:492
DetectFlowPktsToServerRegister
void DetectFlowPktsToServerRegister(void)
Definition: detect-flow-pkts.c:167
Signature_::flags
uint32_t flags
Definition: detect.h:615
Packet_
Definition: decode.h:476
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:404
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1287
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:346
Packet_::flow
struct Flow_ * flow
Definition: decode.h:515
suricata-common.h
DETECT_FLOW_PKTS_TO_SERVER
@ DETECT_FLOW_PKTS_TO_SERVER
Definition: detect-engine-register.h:131
SigTableElmt_::SupportsPrefilter
bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1306
detect-parse.h
Signature_
Signature container.
Definition: detect.h:614
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
SigMatchAppendSMToList
SigMatch * SigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:462
DETECT_FLOW_PKTS_TO_CLIENT
@ DETECT_FLOW_PKTS_TO_CLIENT
Definition: detect-engine-register.h:132
DETECT_FLOW_PKTS
@ DETECT_FLOW_PKTS
Definition: detect-engine-register.h:130
Flow_::tosrcpktcnt
uint32_t tosrcpktcnt
Definition: flow.h:491
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:252