suricata
detect-engine-alert.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2021 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 
20 #include "detect.h"
21 #include "detect-engine-alert.h"
23 #include "detect-engine-tag.h"
24 
25 #include "decode.h"
26 
27 #include "flow.h"
28 #include "flow-private.h"
29 
30 #include "util-profiling.h"
31 
32 /** tag signature we use for tag alerts */
33 static Signature g_tag_signature;
34 /** tag packet alert structure for tag alerts */
35 static PacketAlert g_tag_pa;
36 
38 {
39  memset(&g_tag_signature, 0x00, sizeof(g_tag_signature));
40 
41  g_tag_signature.id = TAG_SIG_ID;
42  g_tag_signature.gid = TAG_SIG_GEN;
43  g_tag_signature.num = TAG_SIG_ID;
44  g_tag_signature.rev = 1;
45  g_tag_signature.prio = 2;
46 
47  memset(&g_tag_pa, 0x00, sizeof(g_tag_pa));
48 
49  g_tag_pa.action = ACTION_ALERT;
50  g_tag_pa.s = &g_tag_signature;
51 }
52 
54 {
55  return &g_tag_pa;
56 }
57 
58 /**
59  * \brief Handle a packet and check if needs a threshold logic
60  * Also apply rule action if necessary.
61  *
62  * \param de_ctx Detection Context
63  * \param sig Signature pointer
64  * \param p Packet structure
65  *
66  * \retval 1 alert is not suppressed
67  * \retval 0 alert is suppressed
68  */
69 static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
70  const Signature *s, Packet *p, PacketAlert *pa)
71 {
72  SCEnter();
73  int ret = 1;
74  const DetectThresholdData *td = NULL;
75  const SigMatchData *smd;
76 
77  if (!(PKT_IS_IPV4(p) || PKT_IS_IPV6(p))) {
78  SCReturnInt(1);
79  }
80 
81  /* handle suppressions first */
82  if (s->sm_arrays[DETECT_SM_LIST_SUPPRESS] != NULL) {
84  smd = NULL;
85  do {
87  if (td != NULL) {
88  SCLogDebug("td %p", td);
89 
90  /* PacketAlertThreshold returns 2 if the alert is suppressed but
91  * we do need to apply rule actions to the packet. */
93  ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s, pa);
94  if (ret == 0 || ret == 2) {
96  /* It doesn't match threshold, remove it */
97  SCReturnInt(ret);
98  }
100  }
101  } while (smd != NULL);
102  }
103 
104  /* if we're still here, consider thresholding */
105  if (s->sm_arrays[DETECT_SM_LIST_THRESHOLD] != NULL) {
107  smd = NULL;
108  do {
110  if (td != NULL) {
111  SCLogDebug("td %p", td);
112 
113  /* PacketAlertThreshold returns 2 if the alert is suppressed but
114  * we do need to apply rule actions to the packet. */
116  ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s, pa);
117  if (ret == 0 || ret == 2) {
119  /* It doesn't match threshold, remove it */
120  SCReturnInt(ret);
121  }
123  }
124  } while (smd != NULL);
125  }
126  SCReturnInt(1);
127 }
128 
129 
130 /**
131  * \brief Check if a certain sid alerted, this is used in the test functions
132  *
133  * \param p Packet on which we want to check if the signature alerted or not
134  * \param sid Signature id of the signature that thas to be checked for a match
135  *
136  * \retval match A value > 0 on a match; 0 on no match
137  */
138 int PacketAlertCheck(Packet *p, uint32_t sid)
139 {
140  uint16_t i = 0;
141  int match = 0;
142 
143  for (i = 0; i < p->alerts.cnt; i++) {
144  if (p->alerts.alerts[i].s == NULL)
145  continue;
146 
147  if (p->alerts.alerts[i].s->id == sid)
148  match++;
149  }
150 
151  return match;
152 }
153 
154 /**
155  * \brief Remove alert from the p->alerts.alerts array at pos
156  * \param p Pointer to the Packet
157  * \param pos Position in the array
158  * \retval 0 if the number of alerts is less than pos
159  * 1 if all goes well
160  */
161 int PacketAlertRemove(Packet *p, uint16_t pos)
162 {
163  uint16_t i = 0;
164  int match = 0;
165 
166  if (pos > p->alerts.cnt) {
167  SCLogDebug("removing %u failed, pos > cnt %u", pos, p->alerts.cnt);
168  return 0;
169  }
170 
171  for (i = pos; i <= p->alerts.cnt - 1; i++) {
172  memcpy(&p->alerts.alerts[i], &p->alerts.alerts[i + 1], sizeof(PacketAlert));
173  }
174 
175  // Update it, since we removed 1
176  p->alerts.cnt--;
177 
178  return match;
179 }
180 
181 /** \brief append a signature match to a packet
182  *
183  * \param det_ctx thread detection engine ctx
184  * \param s the signature that matched
185  * \param p packet
186  * \param flags alert flags
187  */
189  Packet *p, uint64_t tx_id, uint8_t flags)
190 {
191  int i = 0;
192 
193  if (p->alerts.cnt == PACKET_ALERT_MAX)
194  return 0;
195 
196  SCLogDebug("sid %"PRIu32"", s->id);
197 
198  /* It should be usually the last, so check it before iterating */
199  if (p->alerts.cnt == 0 || (p->alerts.cnt > 0 &&
200  p->alerts.alerts[p->alerts.cnt - 1].num < s->num)) {
201  /* We just add it */
202  p->alerts.alerts[p->alerts.cnt].num = s->num;
203  p->alerts.alerts[p->alerts.cnt].action = s->action;
204  p->alerts.alerts[p->alerts.cnt].flags = flags;
205  p->alerts.alerts[p->alerts.cnt].s = s;
206  p->alerts.alerts[p->alerts.cnt].tx_id = tx_id;
207  p->alerts.alerts[p->alerts.cnt].frame_id =
208  (flags & PACKET_ALERT_FLAG_FRAME) ? det_ctx->frame_id : 0;
209  } else {
210  /* We need to make room for this s->num
211  (a bit ugly with memcpy but we are planning changes here)*/
212  for (i = p->alerts.cnt - 1; i >= 0 && p->alerts.alerts[i].num > s->num; i--) {
213  memcpy(&p->alerts.alerts[i + 1], &p->alerts.alerts[i], sizeof(PacketAlert));
214  }
215 
216  i++; /* The right place to store the alert */
217 
218  p->alerts.alerts[i].num = s->num;
219  p->alerts.alerts[i].action = s->action;
220  p->alerts.alerts[i].flags = flags;
221  p->alerts.alerts[i].s = s;
222  p->alerts.alerts[i].tx_id = tx_id;
223  p->alerts.alerts[i].frame_id = (flags & PACKET_ALERT_FLAG_FRAME) ? det_ctx->frame_id : 0;
224  }
225 
226  /* Update the count */
227  p->alerts.cnt++;
228 
229  return 0;
230 }
231 
232 static inline void RuleActionToFlow(const uint8_t action, Flow *f)
233 {
234  if (action & (ACTION_DROP | ACTION_REJECT_ANY | ACTION_PASS)) {
235  if (f->flags & (FLOW_ACTION_DROP | FLOW_ACTION_PASS)) {
236  /* drop or pass already set. First to set wins. */
237  SCLogDebug("not setting %s flow already set to %s",
238  (action & ACTION_PASS) ? "pass" : "drop",
239  (f->flags & FLOW_ACTION_DROP) ? "drop" : "pass");
240  } else {
241  if (action & (ACTION_DROP | ACTION_REJECT_ANY)) {
242  f->flags |= FLOW_ACTION_DROP;
243  SCLogDebug("setting flow action drop");
244  }
245  if (action & ACTION_PASS) {
246  f->flags |= FLOW_ACTION_PASS;
247  SCLogDebug("setting flow action pass");
248  FlowSetNoPacketInspectionFlag(f);
249  }
250  }
251  }
252 }
253 
254 /** \brief Apply action(s) and Set 'drop' sig info,
255  * if applicable */
256 static void PacketApplySignatureActions(Packet *p, const Signature *s, const uint8_t alert_flags)
257 {
258  SCLogDebug("packet %" PRIu64 " sid %u action %02x alert_flags %02x", p->pcap_cnt, s->id,
259  s->action, alert_flags);
260  PacketUpdateAction(p, s->action);
261 
262  if (s->action & ACTION_DROP) {
263  if (p->alerts.drop.action == 0) {
264  p->alerts.drop.num = s->num;
265  p->alerts.drop.action = s->action;
266  p->alerts.drop.s = (Signature *)s;
267  }
268  if ((p->flow != NULL) && (alert_flags & PACKET_ALERT_FLAG_APPLY_ACTION_TO_FLOW)) {
269  RuleActionToFlow(s->action, p->flow);
270  }
271  } else if (s->action & ACTION_PASS) {
272  if ((p->flow != NULL) && (alert_flags & PACKET_ALERT_FLAG_APPLY_ACTION_TO_FLOW)) {
273  RuleActionToFlow(s->action, p->flow);
274  }
275  }
276 }
277 
278 /**
279  * \brief Check the threshold of the sigs that match, set actions, break on pass action
280  * This function iterate the packet alerts array, removing those that didn't match
281  * the threshold, and those that match after a signature with the action "pass".
282  * The array is sorted by action priority/order
283  * \param de_ctx detection engine context
284  * \param det_ctx detection engine thread context
285  * \param p pointer to the packet
286  */
288 {
289  SCEnter();
290  int i = 0;
291 
292  while (i < p->alerts.cnt) {
293  const Signature *s = de_ctx->sig_array[p->alerts.alerts[i].num];
294  SCLogDebug("Sig->num: %" PRIu32 " SID %u", p->alerts.alerts[i].num, s->id);
295 
296  int res = PacketAlertHandle(de_ctx, det_ctx, s, p, &p->alerts.alerts[i]);
297  if (res > 0) {
298  /* Now, if we have an alert, we have to check if we want
299  * to tag this session or src/dst host */
300  if (s->sm_arrays[DETECT_SM_LIST_TMATCH] != NULL) {
303  while (1) {
304  /* tags are set only for alerts */
306  sigmatch_table[smd->type].Match(det_ctx, p, (Signature *)s, smd->ctx);
307  KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
308  if (smd->is_last)
309  break;
310  smd++;
311  }
312  }
313 
314  /* For DROP and PASS sigs we need to apply the action to the flow if
315  * - sig is IP or PD only
316  * - match is in applayer
317  * - match is in stream */
318  if (s->action & (ACTION_DROP | ACTION_PASS)) {
319  if ((p->alerts.alerts[i].flags &
323  SCLogDebug("packet %" PRIu64 " sid %u action %02x alert_flags %02x (set "
324  "PACKET_ALERT_FLAG_APPLY_ACTION_TO_FLOW)",
325  p->pcap_cnt, s->id, s->action, p->alerts.alerts[i].flags);
326  }
327  }
328 
329  /* set actions on packet */
330  PacketApplySignatureActions(p, p->alerts.alerts[i].s, p->alerts.alerts[i].flags);
331 
332  if (PacketTestAction(p, ACTION_PASS)) {
333  /* Ok, reset the alert cnt to end in the previous of pass
334  * so we ignore the rest with less prio */
335  p->alerts.cnt = i;
336  break;
337  }
338  }
339 
340  /* Thresholding removes this alert */
341  if (res == 0 || res == 2 || (s->flags & SIG_FLAG_NOALERT)) {
342  PacketAlertRemove(p, i);
343 
344  if (p->alerts.cnt == 0)
345  break;
346  } else {
347  i++;
348  }
349  }
350 
351  /* At this point, we should have all the new alerts. Now check the tag
352  * keyword context for sessions and hosts */
353  if (!(p->flags & PKT_PSEUDO_STREAM_END))
354  TagHandlePacket(de_ctx, det_ctx, p);
355 
356  /* Set flag on flow to indicate that it has alerts */
357  if (p->flow != NULL && p->alerts.cnt > 0) {
359  }
360 
361 }
362 
363 
FlowSetHasAlertsFlag
void FlowSetHasAlertsFlag(Flow *f)
Set flag to indicate that flow has alerts.
Definition: flow.c:169
PACKET_ALERT_FLAG_STREAM_MATCH
#define PACKET_ALERT_FLAG_STREAM_MATCH
Definition: decode.h:294
PacketAlert_::s
const struct Signature_ * s
Definition: decode.h:284
SIG_FLAG_PDONLY
#define SIG_FLAG_PDONLY
Definition: detect.h:247
PKT_IS_IPV6
#define PKT_IS_IPV6(p)
Definition: decode.h:263
Signature_::num
SigIntId num
Definition: detect.h:557
ACTION_PASS
#define ACTION_PASS
Definition: action-globals.h:34
KEYWORD_PROFILING_SET_LIST
#define KEYWORD_PROFILING_SET_LIST(ctx, list)
Definition: util-profiling.h:65
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:581
PacketAlerts_::alerts
PacketAlert alerts[PACKET_ALERT_MAX]
Definition: decode.h:306
PacketAlerts_::cnt
uint16_t cnt
Definition: decode.h:305
PacketAlertCheck
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
Definition: detect-engine-alert.c:138
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:333
Packet_::flags
uint32_t flags
Definition: decode.h:455
flow-private.h
Flow_
Flow data structure.
Definition: flow.h:353
DETECT_SM_LIST_THRESHOLD
@ DETECT_SM_LIST_THRESHOLD
Definition: detect.h:104
TAG_SIG_ID
#define TAG_SIG_ID
Definition: detect-engine-tag.h:43
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:801
ACTION_REJECT_ANY
#define ACTION_REJECT_ANY
Definition: action-globals.h:37
PacketAlerts_::drop
PacketAlert drop
Definition: decode.h:309
FLOW_ACTION_DROP
#define FLOW_ACTION_DROP
Definition: flow.h:68
Signature_::sm_arrays
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:601
SigMatchData_
Data needed for Match()
Definition: detect.h:330
KEYWORD_PROFILING_START
#define KEYWORD_PROFILING_START
Definition: util-profiling.h:69
SigMatchData_::type
uint16_t type
Definition: detect.h:331
Packet_::alerts
PacketAlerts alerts
Definition: decode.h:575
SIG_FLAG_APPLAYER
#define SIG_FLAG_APPLAYER
Definition: detect.h:218
KEYWORD_PROFILING_END
#define KEYWORD_PROFILING_END(ctx, type, m)
Definition: util-profiling.h:83
PacketAlert_::tx_id
uint64_t tx_id
Definition: decode.h:285
PacketAlert_::action
uint8_t action
Definition: decode.h:282
Signature_::gid
uint32_t gid
Definition: detect.h:581
PacketAlertGetTag
PacketAlert * PacketAlertGetTag(void)
Definition: detect-engine-alert.c:53
FLOW_ACTION_PASS
#define FLOW_ACTION_PASS
Definition: flow.h:115
decode.h
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
DetectEngineThreadCtx_
Definition: detect.h:1050
PacketAlert_::num
SigIntId num
Definition: decode.h:281
DETECT_THRESHOLD
@ DETECT_THRESHOLD
Definition: detect-engine-register.h:55
PKT_PSEUDO_STREAM_END
#define PKT_PSEUDO_STREAM_END
Definition: decode.h:1163
res
PoolThreadReserved res
Definition: stream-tcp-private.h:0
SCEnter
#define SCEnter(...)
Definition: util-debug.h:300
detect.h
detect-engine-tag.h
Signature_::action
uint8_t action
Definition: detect.h:560
util-profiling.h
Signature_::flags
uint32_t flags
Definition: detect.h:547
ACTION_ALERT
#define ACTION_ALERT
Definition: action-globals.h:29
Packet_
Definition: decode.h:420
SIG_FLAG_IPONLY
#define SIG_FLAG_IPONLY
Definition: detect.h:219
DetectEngineThreadCtx_::frame_id
int64_t frame_id
Definition: detect.h:1120
detect-engine-alert.h
PacketAlertRemove
int PacketAlertRemove(Packet *p, uint16_t pos)
Remove alert from the p->alerts.alerts array at pos.
Definition: detect-engine-alert.c:161
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1217
PacketAlertThreshold
int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const DetectThresholdData *td, Packet *p, const Signature *s, PacketAlert *pa)
Make the threshold logic for signatures.
Definition: detect-engine-threshold.c:600
PacketAlert_::frame_id
int64_t frame_id
Definition: decode.h:286
PacketAlert_::flags
uint8_t flags
Definition: decode.h:283
Packet_::flow
struct Flow_ * flow
Definition: decode.h:457
flags
uint8_t flags
Definition: decode-gre.h:0
SigMatchData_::is_last
uint8_t is_last
Definition: detect.h:332
suricata-common.h
DetectThresholdData_
Definition: detect-threshold.h:57
PACKET_ALERT_FLAG_APPLY_ACTION_TO_FLOW
#define PACKET_ALERT_FLAG_APPLY_ACTION_TO_FLOW
Definition: decode.h:290
sigmatch_table
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect-parse.c:73
ACTION_DROP
#define ACTION_DROP
Definition: action-globals.h:30
Signature_::rev
uint32_t rev
Definition: detect.h:582
SIG_FLAG_NOALERT
#define SIG_FLAG_NOALERT
Definition: detect.h:216
DETECT_SM_LIST_TMATCH
@ DETECT_SM_LIST_TMATCH
Definition: detect.h:100
Signature_::prio
int prio
Definition: detect.h:583
SigGetThresholdTypeIter
const DetectThresholdData * SigGetThresholdTypeIter(const Signature *sig, const SigMatchData **psm, int list)
Return next DetectThresholdData for signature.
Definition: detect-engine-threshold.c:113
TagHandlePacket
void TagHandlePacket(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
Search tags for src and dst. Update entries of the tag, remove if necessary.
Definition: detect-engine-tag.c:502
PACKET_ALERT_MAX
#define PACKET_ALERT_MAX
Definition: decode.h:302
PACKET_ALERT_FLAG_FRAME
#define PACKET_ALERT_FLAG_FRAME
Definition: decode.h:300
PacketAlertFinalize
void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
Check the threshold of the sigs that match, set actions, break on pass action This function iterate t...
Definition: detect-engine-alert.c:287
Signature_::id
uint32_t id
Definition: detect.h:580
Flow_::flags
uint32_t flags
Definition: flow.h:431
Signature_
Signature container.
Definition: detect.h:546
PacketAlertTagInit
void PacketAlertTagInit(void)
Definition: detect-engine-alert.c:37
DetectEngineCtx_::sig_array
Signature ** sig_array
Definition: detect.h:816
PacketAlert_
Definition: decode.h:280
PacketAlertAppend
int PacketAlertAppend(DetectEngineThreadCtx *det_ctx, const Signature *s, Packet *p, uint64_t tx_id, uint8_t flags)
append a signature match to a packet
Definition: detect-engine-alert.c:188
TAG_SIG_GEN
#define TAG_SIG_GEN
Definition: detect-engine-tag.h:42
flow.h
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:304
PKT_IS_IPV4
#define PKT_IS_IPV4(p)
Definition: decode.h:262
PACKET_ALERT_FLAG_STATE_MATCH
#define PACKET_ALERT_FLAG_STATE_MATCH
Definition: decode.h:292
DETECT_SM_LIST_SUPPRESS
@ DETECT_SM_LIST_SUPPRESS
Definition: detect.h:103
detect-engine-threshold.h