/src/suricata7/src/detect-engine-alert.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2022 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" |
22 | | #include "detect-engine-threshold.h" |
23 | | #include "detect-engine-tag.h" |
24 | | |
25 | | #include "decode.h" |
26 | | #include "packet.h" |
27 | | |
28 | | #include "flow.h" |
29 | | #include "flow-private.h" |
30 | | |
31 | | #ifdef QA_SIMULATION |
32 | | #include "util-exception-policy.h" |
33 | | #endif |
34 | | |
35 | | #include "util-profiling.h" |
36 | | #include "util-validate.h" |
37 | | |
38 | | #include "action-globals.h" |
39 | | |
40 | | /** tag signature we use for tag alerts */ |
41 | | static Signature g_tag_signature; |
42 | | /** tag packet alert structure for tag alerts */ |
43 | | static PacketAlert g_tag_pa; |
44 | | |
45 | | void PacketAlertTagInit(void) |
46 | 71 | { |
47 | 71 | memset(&g_tag_signature, 0x00, sizeof(g_tag_signature)); |
48 | | |
49 | 71 | g_tag_signature.id = TAG_SIG_ID; |
50 | 71 | g_tag_signature.gid = TAG_SIG_GEN; |
51 | 71 | g_tag_signature.num = TAG_SIG_ID; |
52 | 71 | g_tag_signature.rev = 1; |
53 | 71 | g_tag_signature.prio = 2; |
54 | | |
55 | 71 | memset(&g_tag_pa, 0x00, sizeof(g_tag_pa)); |
56 | | |
57 | 71 | g_tag_pa.action = ACTION_ALERT; |
58 | 71 | g_tag_pa.s = &g_tag_signature; |
59 | 71 | } |
60 | | |
61 | | /** |
62 | | * \brief Handle a packet and check if needs a threshold logic |
63 | | * Also apply rule action if necessary. |
64 | | * |
65 | | * \param de_ctx Detection Context |
66 | | * \param sig Signature pointer |
67 | | * \param p Packet structure |
68 | | * |
69 | | * \retval 1 alert is not suppressed |
70 | | * \retval 0 alert is suppressed |
71 | | */ |
72 | | static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, |
73 | | const Signature *s, Packet *p, PacketAlert *pa) |
74 | 461k | { |
75 | 461k | SCEnter(); |
76 | 461k | int ret = 1; |
77 | 461k | const DetectThresholdData *td = NULL; |
78 | 461k | const SigMatchData *smd; |
79 | | |
80 | 461k | if (!(PKT_IS_IPV4(p) || PKT_IS_IPV6(p))) { |
81 | 1.20k | SCReturnInt(1); |
82 | 1.20k | } |
83 | | |
84 | | /* handle suppressions first */ |
85 | 459k | if (s->sm_arrays[DETECT_SM_LIST_SUPPRESS] != NULL) { |
86 | 0 | KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_SUPPRESS); |
87 | 0 | smd = NULL; |
88 | 0 | do { |
89 | 0 | td = SigGetThresholdTypeIter(s, &smd, DETECT_SM_LIST_SUPPRESS); |
90 | 0 | if (td != NULL) { |
91 | 0 | SCLogDebug("td %p", td); |
92 | | |
93 | | /* PacketAlertThreshold returns 2 if the alert is suppressed but |
94 | | * we do need to apply rule actions to the packet. */ |
95 | 0 | KEYWORD_PROFILING_START; |
96 | 0 | ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s, pa); |
97 | 0 | if (ret == 0 || ret == 2) { |
98 | 0 | KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD, 0); |
99 | | /* It doesn't match threshold, remove it */ |
100 | 0 | SCReturnInt(ret); |
101 | 0 | } |
102 | 0 | KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD, 1); |
103 | 0 | } |
104 | 0 | } while (smd != NULL); |
105 | 0 | } |
106 | | |
107 | | /* if we're still here, consider thresholding */ |
108 | 459k | if (s->sm_arrays[DETECT_SM_LIST_THRESHOLD] != NULL) { |
109 | 2.58k | KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_THRESHOLD); |
110 | 2.58k | smd = NULL; |
111 | 2.58k | do { |
112 | 2.58k | td = SigGetThresholdTypeIter(s, &smd, DETECT_SM_LIST_THRESHOLD); |
113 | 2.58k | if (td != NULL) { |
114 | 2.58k | SCLogDebug("td %p", td); |
115 | | |
116 | | /* PacketAlertThreshold returns 2 if the alert is suppressed but |
117 | | * we do need to apply rule actions to the packet. */ |
118 | 2.58k | KEYWORD_PROFILING_START; |
119 | 2.58k | ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s, pa); |
120 | 2.58k | if (ret == 0 || ret == 2) { |
121 | 2.26k | KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD ,0); |
122 | | /* It doesn't match threshold, remove it */ |
123 | 2.26k | SCReturnInt(ret); |
124 | 2.26k | } |
125 | 319 | KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD, 1); |
126 | 319 | } |
127 | 2.58k | } while (smd != NULL); |
128 | 2.58k | } |
129 | 459k | SCReturnInt(1); |
130 | 459k | } |
131 | | |
132 | | #ifdef UNITTESTS |
133 | | /** |
134 | | * \brief Check if a certain sid alerted, this is used in the test functions |
135 | | * |
136 | | * \param p Packet on which we want to check if the signature alerted or not |
137 | | * \param sid Signature id of the signature that has to be checked for a match |
138 | | * |
139 | | * \retval match A value > 0 on a match; 0 on no match |
140 | | */ |
141 | | int PacketAlertCheck(Packet *p, uint32_t sid) |
142 | | { |
143 | | int match = 0; |
144 | | |
145 | | for (uint16_t i = 0; i < p->alerts.cnt; i++) { |
146 | | BUG_ON(p->alerts.alerts[i].s == NULL); |
147 | | if (p->alerts.alerts[i].s->id == sid) |
148 | | match++; |
149 | | } |
150 | | |
151 | | return match; |
152 | | } |
153 | | #endif |
154 | | |
155 | | static inline void RuleActionToFlow(const uint8_t action, Flow *f) |
156 | 2.26k | { |
157 | 2.26k | if (action & (ACTION_DROP | ACTION_REJECT_ANY | ACTION_PASS)) { |
158 | 2.26k | if (f->flags & (FLOW_ACTION_DROP | FLOW_ACTION_PASS)) { |
159 | | /* drop or pass already set. First to set wins. */ |
160 | 0 | SCLogDebug("not setting %s flow already set to %s", |
161 | 0 | (action & ACTION_PASS) ? "pass" : "drop", |
162 | 0 | (f->flags & FLOW_ACTION_DROP) ? "drop" : "pass"); |
163 | 2.26k | } else { |
164 | 2.26k | if (action & (ACTION_DROP | ACTION_REJECT_ANY)) { |
165 | 171 | f->flags |= FLOW_ACTION_DROP; |
166 | 171 | SCLogDebug("setting flow action drop"); |
167 | 171 | } |
168 | 2.26k | if (action & ACTION_PASS) { |
169 | 2.09k | f->flags |= FLOW_ACTION_PASS; |
170 | 2.09k | SCLogDebug("setting flow action pass"); |
171 | 2.09k | FlowSetNoPacketInspectionFlag(f); |
172 | 2.09k | } |
173 | 2.26k | } |
174 | 2.26k | } |
175 | 2.26k | } |
176 | | |
177 | | /** \brief Apply action(s) and Set 'drop' sig info, |
178 | | * if applicable |
179 | | * \param p packet |
180 | | * \param s signature -- for id, sig pointer, not actions |
181 | | * \param pa packet alert struct -- match, including actions after thresholding (rate_filter) */ |
182 | | static void PacketApplySignatureActions(Packet *p, const Signature *s, const PacketAlert *pa) |
183 | 459k | { |
184 | 459k | SCLogDebug("packet %" PRIu64 " sid %u action %02x alert_flags %02x", p->pcap_cnt, s->id, |
185 | 459k | pa->action, pa->flags); |
186 | | |
187 | | /* REJECT also sets ACTION_DROP, just make it more visible with this check */ |
188 | 459k | if (pa->action & ACTION_DROP_REJECT) { |
189 | | /* PacketDrop will update the packet action, too */ |
190 | 1.51k | PacketDrop(p, pa->action, |
191 | 1.51k | (pa->flags & PACKET_ALERT_RATE_FILTER_MODIFIED) ? PKT_DROP_REASON_RULES_THRESHOLD |
192 | 1.51k | : PKT_DROP_REASON_RULES); |
193 | 1.51k | SCLogDebug("[packet %p][DROP sid %u]", p, s->id); |
194 | | |
195 | 1.51k | if (p->alerts.drop.action == 0) { |
196 | 0 | p->alerts.drop.num = s->num; |
197 | 0 | p->alerts.drop.action = pa->action; |
198 | 0 | p->alerts.drop.s = (Signature *)s; |
199 | 0 | } |
200 | 1.51k | if ((p->flow != NULL) && (pa->flags & PACKET_ALERT_FLAG_APPLY_ACTION_TO_FLOW)) { |
201 | 171 | RuleActionToFlow(pa->action, p->flow); |
202 | 171 | } |
203 | | |
204 | 1.51k | DEBUG_VALIDATE_BUG_ON(!PacketCheckAction(p, ACTION_DROP)); |
205 | 458k | } else { |
206 | 458k | if (pa->action & ACTION_PASS) { |
207 | 5.14k | SCLogDebug("[packet %p][PASS sid %u]", p, s->id); |
208 | | // nothing to set in the packet |
209 | 452k | } else if (pa->action & (ACTION_ALERT | ACTION_CONFIG)) { |
210 | | // nothing to set in the packet |
211 | 445k | } else if (pa->action != 0) { |
212 | 0 | DEBUG_VALIDATE_BUG_ON(1); // should be unreachable |
213 | 0 | } |
214 | | |
215 | 458k | if ((pa->action & ACTION_PASS) && (p->flow != NULL) && |
216 | 2.48k | (pa->flags & PACKET_ALERT_FLAG_APPLY_ACTION_TO_FLOW)) { |
217 | 2.09k | RuleActionToFlow(pa->action, p->flow); |
218 | 2.09k | } |
219 | 458k | } |
220 | 459k | } |
221 | | |
222 | | void AlertQueueInit(DetectEngineThreadCtx *det_ctx) |
223 | 146k | { |
224 | 146k | det_ctx->alert_queue_size = 0; |
225 | 146k | det_ctx->alert_queue = SCCalloc(packet_alert_max, sizeof(PacketAlert)); |
226 | 146k | if (det_ctx->alert_queue == NULL) { |
227 | 0 | FatalError("failed to allocate %" PRIu64 " bytes for the alert queue", |
228 | 0 | (uint64_t)(packet_alert_max * sizeof(PacketAlert))); |
229 | 0 | } |
230 | 146k | det_ctx->alert_queue_capacity = packet_alert_max; |
231 | 146k | SCLogDebug("alert queue initialized to %u elements (%" PRIu64 " bytes)", packet_alert_max, |
232 | 146k | (uint64_t)(packet_alert_max * sizeof(PacketAlert))); |
233 | 146k | } |
234 | | |
235 | | void AlertQueueFree(DetectEngineThreadCtx *det_ctx) |
236 | 146k | { |
237 | 146k | SCFree(det_ctx->alert_queue); |
238 | 146k | det_ctx->alert_queue_capacity = 0; |
239 | 146k | } |
240 | | |
241 | | static inline uint16_t AlertQueueExpandDo(DetectEngineThreadCtx *det_ctx, uint16_t new_cap) |
242 | 401 | { |
243 | 401 | DEBUG_VALIDATE_BUG_ON(det_ctx->alert_queue_capacity >= new_cap); |
244 | | |
245 | 401 | void *tmp_queue = SCRealloc(det_ctx->alert_queue, new_cap * sizeof(PacketAlert)); |
246 | 401 | if (unlikely(tmp_queue == NULL)) { |
247 | | /* queue capacity didn't change */ |
248 | 0 | return det_ctx->alert_queue_capacity; |
249 | 0 | } |
250 | 401 | det_ctx->alert_queue = tmp_queue; |
251 | 401 | det_ctx->alert_queue_capacity = new_cap; |
252 | 401 | SCLogDebug("Alert queue size expanded: %u elements, bytes: %" PRIuMAX "", |
253 | 401 | det_ctx->alert_queue_capacity, (uintmax_t)(new_cap * sizeof(PacketAlert))); |
254 | 401 | return new_cap; |
255 | 401 | } |
256 | | |
257 | | /** \internal |
258 | | * \retval the new capacity |
259 | | */ |
260 | | static uint16_t AlertQueueExpand(DetectEngineThreadCtx *det_ctx) |
261 | 401 | { |
262 | | #ifdef QA_SIMULATION |
263 | | if (unlikely(g_eps_is_alert_queue_fail_mode)) |
264 | | return det_ctx->alert_queue_capacity; |
265 | | #endif |
266 | 401 | if (det_ctx->alert_queue_capacity == UINT16_MAX) { |
267 | 0 | return det_ctx->alert_queue_capacity; |
268 | 0 | } |
269 | | |
270 | 401 | uint16_t new_cap; |
271 | 401 | if (det_ctx->alert_queue_capacity > (UINT16_MAX / 2)) { |
272 | 0 | new_cap = UINT16_MAX; |
273 | 401 | } else { |
274 | 401 | new_cap = det_ctx->alert_queue_capacity * 2; |
275 | 401 | } |
276 | 401 | return AlertQueueExpandDo(det_ctx, new_cap); |
277 | 401 | } |
278 | | |
279 | | /** \internal |
280 | | */ |
281 | | static inline PacketAlert PacketAlertSet( |
282 | | DetectEngineThreadCtx *det_ctx, const Signature *s, uint64_t tx_id, uint8_t alert_flags) |
283 | 1.05M | { |
284 | 1.05M | PacketAlert pa; |
285 | 1.05M | pa.num = s->num; |
286 | 1.05M | pa.action = s->action; |
287 | 1.05M | pa.s = (Signature *)s; |
288 | 1.05M | pa.flags = alert_flags; |
289 | | /* Set tx_id if the frame has it */ |
290 | 1.05M | pa.tx_id = tx_id; |
291 | 1.05M | pa.frame_id = (alert_flags & PACKET_ALERT_FLAG_FRAME) ? det_ctx->frame_id : 0; |
292 | 1.05M | return pa; |
293 | 1.05M | } |
294 | | |
295 | | /** |
296 | | * \brief Append signature to local packet alert queue for later preprocessing |
297 | | */ |
298 | | void AlertQueueAppend(DetectEngineThreadCtx *det_ctx, const Signature *s, Packet *p, uint64_t tx_id, |
299 | | uint8_t alert_flags) |
300 | 463k | { |
301 | | /* first time we see a drop action signature, set that in the packet */ |
302 | | /* we do that even before inserting into the queue, so we save it even if appending fails */ |
303 | 463k | if (p->alerts.drop.action == 0 && s->action & ACTION_DROP) { |
304 | 1.80k | p->alerts.drop = PacketAlertSet(det_ctx, s, tx_id, alert_flags); |
305 | 1.80k | SCLogDebug("Set PacketAlert drop action. s->num %" PRIu32 "", s->num); |
306 | 1.80k | } |
307 | | |
308 | 463k | uint16_t pos = det_ctx->alert_queue_size; |
309 | 463k | if (pos == det_ctx->alert_queue_capacity) { |
310 | | /* we must grow the alert queue */ |
311 | 330 | if (pos == AlertQueueExpand(det_ctx)) { |
312 | | /* this means we failed to expand the queue */ |
313 | 0 | p->alerts.discarded++; |
314 | 0 | return; |
315 | 0 | } |
316 | 330 | } |
317 | 463k | det_ctx->alert_queue[pos] = PacketAlertSet(det_ctx, s, tx_id, alert_flags); |
318 | | |
319 | 463k | SCLogDebug("Appending sid %" PRIu32 ", s->num %" PRIu32 " to alert queue", s->id, s->num); |
320 | 463k | det_ctx->alert_queue_size++; |
321 | 463k | return; |
322 | 463k | } |
323 | | |
324 | | /** \internal |
325 | | * \brief sort helper for sorting alerts by priority |
326 | | * |
327 | | * Sorting is done first based on num and then using tx_id, if nums are equal. |
328 | | * The Signature::num field is set based on internal priority. Higher priority |
329 | | * rules have lower nums. |
330 | | */ |
331 | | static int AlertQueueSortHelper(const void *a, const void *b) |
332 | 183k | { |
333 | 183k | const PacketAlert *pa0 = a; |
334 | 183k | const PacketAlert *pa1 = b; |
335 | 183k | if (pa1->num == pa0->num) { |
336 | 133k | if (pa1->tx_id == PACKET_ALERT_NOTX) { |
337 | 0 | return -1; |
338 | 133k | } else if (pa0->tx_id == PACKET_ALERT_NOTX) { |
339 | 0 | return 1; |
340 | 0 | } |
341 | 133k | return pa0->tx_id < pa1->tx_id ? 1 : -1; |
342 | 133k | } |
343 | 50.6k | return pa0->num > pa1->num ? 1 : -1; |
344 | 183k | } |
345 | | |
346 | | /** \internal |
347 | | * \brief Check if Signature action should be applied to flow and apply |
348 | | * |
349 | | */ |
350 | | static inline void FlowApplySignatureActions( |
351 | | Packet *p, PacketAlert *pa, const Signature *s, uint8_t alert_flags) |
352 | 459k | { |
353 | | /* For DROP and PASS sigs we need to apply the action to the flow if |
354 | | * - sig is IP or PD only |
355 | | * - match is in applayer |
356 | | * - match is in stream */ |
357 | 459k | if (pa->action & (ACTION_DROP | ACTION_PASS)) { |
358 | 6.66k | DEBUG_VALIDATE_BUG_ON(s->type == SIG_TYPE_NOT_SET); |
359 | 6.66k | DEBUG_VALIDATE_BUG_ON(s->type == SIG_TYPE_MAX); |
360 | | |
361 | 6.66k | enum SignaturePropertyFlowAction flow_action = signature_properties[s->type].flow_action; |
362 | 6.66k | if (flow_action == SIG_PROP_FLOW_ACTION_FLOW) { |
363 | 4.96k | pa->flags |= PACKET_ALERT_FLAG_APPLY_ACTION_TO_FLOW; |
364 | 4.96k | } else if (flow_action == SIG_PROP_FLOW_ACTION_FLOW_IF_STATEFUL) { |
365 | 5 | if (pa->flags & (PACKET_ALERT_FLAG_STATE_MATCH | PACKET_ALERT_FLAG_STREAM_MATCH)) { |
366 | 1 | pa->flags |= PACKET_ALERT_FLAG_APPLY_ACTION_TO_FLOW; |
367 | 1 | } |
368 | 5 | } |
369 | | |
370 | 6.66k | if (pa->flags & PACKET_ALERT_FLAG_APPLY_ACTION_TO_FLOW) { |
371 | 4.96k | SCLogDebug("packet %" PRIu64 " sid %u action %02x alert_flags %02x (set " |
372 | 4.96k | "PACKET_ALERT_FLAG_APPLY_ACTION_TO_FLOW)", |
373 | 4.96k | p->pcap_cnt, s->id, s->action, pa->flags); |
374 | 4.96k | } |
375 | 6.66k | } |
376 | 459k | } |
377 | | |
378 | | /** |
379 | | * \brief Check the threshold of the sigs that match, set actions, break on pass action |
380 | | * This function iterate the packet alerts array, removing those that didn't match |
381 | | * the threshold, and those that match after a signature with the action "pass". |
382 | | * The array is sorted by action priority/order |
383 | | * \param de_ctx detection engine context |
384 | | * \param det_ctx detection engine thread context |
385 | | * \param p pointer to the packet |
386 | | */ |
387 | | void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p) |
388 | 9.73M | { |
389 | 9.73M | SCEnter(); |
390 | | |
391 | | /* sort the alert queue before thresholding and appending to Packet */ |
392 | 9.73M | qsort(det_ctx->alert_queue, det_ctx->alert_queue_size, sizeof(PacketAlert), |
393 | 9.73M | AlertQueueSortHelper); |
394 | | |
395 | 10.1M | for (uint16_t i = 0; i < det_ctx->alert_queue_size; i++) { |
396 | 461k | PacketAlert *pa = &det_ctx->alert_queue[i]; |
397 | 461k | const Signature *s = de_ctx->sig_array[pa->num]; |
398 | 461k | int res = PacketAlertHandle(de_ctx, det_ctx, s, p, pa); |
399 | 461k | if (res > 0) { |
400 | | /* Now, if we have an alert, we have to check if we want |
401 | | * to tag this session or src/dst host */ |
402 | 459k | if (s->sm_arrays[DETECT_SM_LIST_TMATCH] != NULL) { |
403 | 1.68k | KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_TMATCH); |
404 | 1.68k | SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_TMATCH]; |
405 | 2.88k | while (1) { |
406 | | /* tags are set only for alerts */ |
407 | 2.88k | KEYWORD_PROFILING_START; |
408 | 2.88k | sigmatch_table[smd->type].Match(det_ctx, p, (Signature *)s, smd->ctx); |
409 | 2.88k | KEYWORD_PROFILING_END(det_ctx, smd->type, 1); |
410 | 2.88k | if (smd->is_last) |
411 | 1.68k | break; |
412 | 1.20k | smd++; |
413 | 1.20k | } |
414 | 1.68k | } |
415 | | |
416 | 459k | bool skip_action_set = false; |
417 | 459k | if (p->action & ACTION_DROP) { |
418 | 47 | if (pa->action & ACTION_PASS) { |
419 | 0 | skip_action_set = true; |
420 | 0 | } |
421 | 47 | } |
422 | 459k | if (!skip_action_set) { |
423 | | /* set actions on the flow */ |
424 | 459k | FlowApplySignatureActions(p, pa, s, pa->flags); |
425 | | |
426 | 459k | SCLogDebug("det_ctx->alert_queue[i].action %02x (DROP %s, PASS %s)", pa->action, |
427 | 459k | BOOL2STR(pa->action & ACTION_DROP), BOOL2STR(pa->action & ACTION_PASS)); |
428 | | |
429 | | /* set actions on packet */ |
430 | 459k | PacketApplySignatureActions(p, s, pa); |
431 | 459k | } |
432 | 459k | } |
433 | | |
434 | | /* Thresholding removes this alert */ |
435 | 461k | if (res == 0 || res == 2 || (s->action & (ACTION_ALERT | ACTION_PASS)) == 0) { |
436 | 9.90k | SCLogDebug("sid:%u: skipping alert because of thresholding (res=%d) or NOALERT (%02x)", |
437 | 9.90k | s->id, res, s->action); |
438 | | /* we will not copy this to the AlertQueue */ |
439 | 9.90k | p->alerts.suppressed++; |
440 | 451k | } else if (p->alerts.cnt < packet_alert_max) { |
441 | 426k | p->alerts.alerts[p->alerts.cnt] = *pa; |
442 | 426k | SCLogDebug("Appending sid %" PRIu32 " alert to Packet::alerts at pos %u", s->id, i); |
443 | | |
444 | | /* pass w/o alert found, we're done. Alert is not logged. */ |
445 | 426k | if ((pa->action & (ACTION_PASS | ACTION_ALERT)) == ACTION_PASS) { |
446 | 5.02k | SCLogDebug("sid:%u: is a pass rule, so break out of loop", s->id); |
447 | 5.02k | break; |
448 | 5.02k | } |
449 | 421k | p->alerts.cnt++; |
450 | | |
451 | | /* pass with alert, we're done. Alert is logged. */ |
452 | 421k | if (pa->action & ACTION_PASS) { |
453 | 126 | SCLogDebug("sid:%u: is a pass rule, so break out of loop", s->id); |
454 | 126 | break; |
455 | 126 | } |
456 | 421k | } else { |
457 | 25.0k | p->alerts.discarded++; |
458 | 25.0k | } |
459 | 461k | } |
460 | | |
461 | | /* At this point, we should have all the new alerts. Now check the tag |
462 | | * keyword context for sessions and hosts */ |
463 | 9.73M | if (!(p->flags & PKT_PSEUDO_STREAM_END)) |
464 | 9.58M | TagHandlePacket(de_ctx, det_ctx, p); |
465 | | |
466 | | /* Set flag on flow to indicate that it has alerts */ |
467 | 9.73M | if (p->flow != NULL && p->alerts.cnt > 0) { |
468 | 351k | if (!FlowHasAlerts(p->flow)) { |
469 | 30.5k | FlowSetHasAlertsFlag(p->flow); |
470 | 30.5k | p->flags |= PKT_FIRST_ALERTS; |
471 | 30.5k | } |
472 | 351k | } |
473 | 9.73M | } |
474 | | |
475 | | #ifdef UNITTESTS |
476 | | #include "tests/detect-engine-alert.c" |
477 | | #endif |