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
26static 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
47static void DetectFlowPktsFree(DetectEngineCtx *de_ctx, void *ptr)
48{
49 if (ptr != NULL) {
50 SCDetectFlowPktsFree(ptr);
51 }
52}
53
54static 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
71static 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
87static 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
104static 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
114static 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
124static 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
143static int PrefilterSetupFlowPkts(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
144{
146 PrefilterPacketFlowPktsSet, PrefilterPacketFlowPktsCompare,
147 PrefilterPacketFlowPktsMatch);
148}
149
150static 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;
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;
191}
192
193static 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
214static void DetectFlowBytesFree(DetectEngineCtx *de_ctx, void *ptr)
215{
216 if (ptr != NULL) {
217 SCDetectFlowBytesFree(ptr);
218 }
219}
220
221static 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
238static 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
255static 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}
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))
@ DETECT_FLOW_BYTES
@ DETECT_FLOW_PKTS_TO_SERVER
@ DETECT_FLOW_BYTES_TO_CLIENT
@ DETECT_FLOW_BYTES_TO_SERVER
@ DETECT_FLOW_PKTS_TO_CLIENT
int DetectU32Match(const uint32_t parg, const DetectUintData_u32 *du32)
int DetectU64Match(const uint64_t parg, const DetectUintData_u64 *du64)
void DetectFlowBytesToServerRegister(void)
void DetectFlowPktsRegister(void)
void DetectFlowBytesRegister(void)
void DetectFlowBytesToClientRegister(void)
void DetectFlowPktsToClientRegister(void)
void DetectFlowPktsToServerRegister(void)
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
SigTableElmt * sigmatch_table
#define SIG_MASK_REQUIRE_FLOW
Definition detect.h:312
#define SIG_FLAG_REQUIRE_PACKET
Definition detect.h:254
@ DETECT_SM_LIST_MATCH
Definition detect.h:117
DetectEngineCtx * de_ctx
struct Thresholds ctx
main detection engine ctx
Definition detect.h:932
PrefilterRuleStore pmq
Definition detect.h:1349
uint64_t tosrcbytecnt
Definition flow.h:498
uint64_t todstbytecnt
Definition flow.h:497
uint32_t todstpktcnt
Definition flow.h:495
uint32_t tosrcpktcnt
Definition flow.h:496
struct Flow_ * flow
Definition decode.h:546
Container for matching data for a signature group.
Definition detect.h:1629
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition detect.h:351
const char * url
Definition detect.h:1462
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition detect.h:1444
void(* Free)(DetectEngineCtx *, void *)
Definition detect.h:1446
const char * desc
Definition detect.h:1461
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition detect.h:1421
const char * name
Definition detect.h:1459
bool(* SupportsPrefilter)(const Signature *s)
Definition detect.h:1443
Signature container.
Definition detect.h:668
uint32_t flags
Definition detect.h:669