aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/detect-engine-alert.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/suricata/src/detect-engine-alert.c')
-rw-r--r--framework/src/suricata/src/detect-engine-alert.c337
1 files changed, 337 insertions, 0 deletions
diff --git a/framework/src/suricata/src/detect-engine-alert.c b/framework/src/suricata/src/detect-engine-alert.c
new file mode 100644
index 00000000..c2d7e420
--- /dev/null
+++ b/framework/src/suricata/src/detect-engine-alert.c
@@ -0,0 +1,337 @@
+/* Copyright (C) 2007-2011 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "suricata-common.h"
+
+#include "detect.h"
+#include "detect-engine-alert.h"
+#include "detect-engine-threshold.h"
+#include "detect-engine-tag.h"
+
+#include "decode.h"
+
+#include "flow.h"
+#include "flow-private.h"
+
+#include "util-profiling.h"
+
+/** tag signature we use for tag alerts */
+static Signature g_tag_signature;
+/** tag packet alert structure for tag alerts */
+static PacketAlert g_tag_pa;
+
+void PacketAlertTagInit(void)
+{
+ memset(&g_tag_signature, 0x00, sizeof(g_tag_signature));
+
+ g_tag_signature.id = TAG_SIG_ID;
+ g_tag_signature.gid = TAG_SIG_GEN;
+ g_tag_signature.num = TAG_SIG_ID;
+ g_tag_signature.rev = 1;
+ g_tag_signature.prio = 2;
+
+ memset(&g_tag_pa, 0x00, sizeof(g_tag_pa));
+
+ g_tag_pa.action = ACTION_ALERT;
+ g_tag_pa.s = &g_tag_signature;
+}
+
+PacketAlert *PacketAlertGetTag(void)
+{
+ return &g_tag_pa;
+}
+
+/**
+ * \brief Handle a packet and check if needs a threshold logic
+ * Also apply rule action if necessary.
+ *
+ * \param de_ctx Detection Context
+ * \param sig Signature pointer
+ * \param p Packet structure
+ *
+ * \retval 1 alert is not suppressed
+ * \retval 0 alert is suppressed
+ */
+static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
+ Signature *s, Packet *p, uint16_t pos)
+{
+ SCEnter();
+ int ret = 1;
+ DetectThresholdData *td = NULL;
+ SigMatch *sm;
+
+ if (!(PKT_IS_IPV4(p) || PKT_IS_IPV6(p))) {
+ SCReturnInt(1);
+ }
+
+ /* handle suppressions first */
+ if (s->sm_lists[DETECT_SM_LIST_SUPPRESS] != NULL) {
+ KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_SUPPRESS);
+ sm = NULL;
+ do {
+ td = SigGetThresholdTypeIter(s, p, &sm, DETECT_SM_LIST_SUPPRESS);
+ if (td != NULL) {
+ SCLogDebug("td %p", td);
+
+ /* PacketAlertThreshold returns 2 if the alert is suppressed but
+ * we do need to apply rule actions to the packet. */
+ KEYWORD_PROFILING_START;
+ ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s);
+ if (ret == 0 || ret == 2) {
+ KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD, 0);
+ /* It doesn't match threshold, remove it */
+ SCReturnInt(ret);
+ }
+ KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD, 1);
+ }
+ } while (sm != NULL);
+ }
+
+ /* if we're still here, consider thresholding */
+ if (s->sm_lists[DETECT_SM_LIST_THRESHOLD] != NULL) {
+ KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_THRESHOLD);
+ sm = NULL;
+ do {
+ td = SigGetThresholdTypeIter(s, p, &sm, DETECT_SM_LIST_THRESHOLD);
+ if (td != NULL) {
+ SCLogDebug("td %p", td);
+
+ /* PacketAlertThreshold returns 2 if the alert is suppressed but
+ * we do need to apply rule actions to the packet. */
+ KEYWORD_PROFILING_START;
+ ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s);
+ if (ret == 0 || ret == 2) {
+ KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD ,0);
+ /* It doesn't match threshold, remove it */
+ SCReturnInt(ret);
+ }
+ KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD, 1);
+ }
+ } while (sm != NULL);
+ }
+ SCReturnInt(1);
+}
+
+
+/**
+ * \brief Check if a certain sid alerted, this is used in the test functions
+ *
+ * \param p Packet on which we want to check if the signature alerted or not
+ * \param sid Signature id of the signature that thas to be checked for a match
+ *
+ * \retval match A value > 0 on a match; 0 on no match
+ */
+int PacketAlertCheck(Packet *p, uint32_t sid)
+{
+ uint16_t i = 0;
+ int match = 0;
+
+ for (i = 0; i < p->alerts.cnt; i++) {
+ if (p->alerts.alerts[i].s == NULL)
+ continue;
+
+ if (p->alerts.alerts[i].s->id == sid)
+ match++;
+ }
+
+ return match;
+}
+
+/**
+ * \brief Remove alert from the p->alerts.alerts array at pos
+ * \param p Pointer to the Packet
+ * \param pos Position in the array
+ * \retval 0 if the number of alerts is less than pos
+ * 1 if all goes well
+ */
+int PacketAlertRemove(Packet *p, uint16_t pos)
+{
+ uint16_t i = 0;
+ int match = 0;
+
+ if (pos > p->alerts.cnt) {
+ SCLogDebug("removing %u failed, pos > cnt %u", pos, p->alerts.cnt);
+ return 0;
+ }
+
+ for (i = pos; i <= p->alerts.cnt - 1; i++) {
+ memcpy(&p->alerts.alerts[i], &p->alerts.alerts[i + 1], sizeof(PacketAlert));
+ }
+
+ // Update it, since we removed 1
+ p->alerts.cnt--;
+
+ return match;
+}
+
+/** \brief append a signature match to a packet
+ *
+ * \param det_ctx thread detection engine ctx
+ * \param s the signature that matched
+ * \param p packet
+ * \param flags alert flags
+ * \param alert_msg ptr to StreamMsg object that the signature matched on
+ */
+int PacketAlertAppend(DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p, uint64_t tx_id, uint8_t flags)
+{
+ int i = 0;
+
+ if (p->alerts.cnt == PACKET_ALERT_MAX)
+ return 0;
+
+ SCLogDebug("sid %"PRIu32"", s->id);
+
+ /* It should be usually the last, so check it before iterating */
+ if (p->alerts.cnt == 0 || (p->alerts.cnt > 0 &&
+ p->alerts.alerts[p->alerts.cnt - 1].num < s->num)) {
+ /* We just add it */
+ p->alerts.alerts[p->alerts.cnt].num = s->num;
+ p->alerts.alerts[p->alerts.cnt].action = s->action;
+ p->alerts.alerts[p->alerts.cnt].flags = flags;
+ p->alerts.alerts[p->alerts.cnt].s = s;
+ p->alerts.alerts[p->alerts.cnt].tx_id = tx_id;
+ } else {
+ /* We need to make room for this s->num
+ (a bit ugly with memcpy but we are planning changes here)*/
+ for (i = p->alerts.cnt - 1; i >= 0 && p->alerts.alerts[i].num > s->num; i--) {
+ memcpy(&p->alerts.alerts[i + 1], &p->alerts.alerts[i], sizeof(PacketAlert));
+ }
+
+ i++; /* The right place to store the alert */
+
+ p->alerts.alerts[i].num = s->num;
+ p->alerts.alerts[i].action = s->action;
+ p->alerts.alerts[i].flags = flags;
+ p->alerts.alerts[i].s = s;
+ p->alerts.alerts[i].tx_id = tx_id;
+ }
+
+ /* Update the count */
+ p->alerts.cnt++;
+
+ return 0;
+}
+
+/**
+ * \brief Check the threshold of the sigs that match, set actions, break on pass action
+ * This function iterate the packet alerts array, removing those that didn't match
+ * the threshold, and those that match after a signature with the action "pass".
+ * The array is sorted by action priority/order
+ * \param de_ctx detection engine context
+ * \param det_ctx detection engine thread context
+ * \param p pointer to the packet
+ */
+void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
+{
+ SCEnter();
+ int i = 0;
+ Signature *s = NULL;
+ SigMatch *sm = NULL;
+
+ while (i < p->alerts.cnt) {
+ SCLogDebug("Sig->num: %"PRIu16, p->alerts.alerts[i].num);
+ s = de_ctx->sig_array[p->alerts.alerts[i].num];
+
+ int res = PacketAlertHandle(de_ctx, det_ctx, s, p, i);
+ if (res > 0) {
+ /* Now, if we have an alert, we have to check if we want
+ * to tag this session or src/dst host */
+ KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_TMATCH);
+ sm = s->sm_lists[DETECT_SM_LIST_TMATCH];
+ while (sm) {
+ /* tags are set only for alerts */
+ KEYWORD_PROFILING_START;
+ sigmatch_table[sm->type].Match(NULL, det_ctx, p, s, sm->ctx);
+ KEYWORD_PROFILING_END(det_ctx, sm->type, 1);
+ sm = sm->next;
+ }
+
+ if (s->flags & SIG_FLAG_IPONLY) {
+ if (((p->flowflags & FLOW_PKT_TOSERVER) && !(p->flowflags & FLOW_PKT_TOSERVER_IPONLY_SET)) ||
+ ((p->flowflags & FLOW_PKT_TOCLIENT) && !(p->flowflags & FLOW_PKT_TOCLIENT_IPONLY_SET))) {
+ SCLogDebug("testing against \"ip-only\" signatures");
+
+ if (p->flow != NULL) {
+ /* Update flow flags for iponly */
+ FLOWLOCK_WRLOCK(p->flow);
+ FlowSetIPOnlyFlagNoLock(p->flow, p->flowflags & FLOW_PKT_TOSERVER ? 1 : 0);
+
+ if (s->action & ACTION_DROP)
+ p->flow->flags |= FLOW_ACTION_DROP;
+ if (s->action & ACTION_REJECT)
+ p->flow->flags |= FLOW_ACTION_DROP;
+ if (s->action & ACTION_REJECT_DST)
+ p->flow->flags |= FLOW_ACTION_DROP;
+ if (s->action & ACTION_REJECT_BOTH)
+ p->flow->flags |= FLOW_ACTION_DROP;
+ if (s->action & ACTION_PASS) {
+ FlowSetNoPacketInspectionFlag(p->flow);
+ }
+ FLOWLOCK_UNLOCK(p->flow);
+ }
+ }
+ }
+
+ /* set actions on packet */
+ DetectSignatureApplyActions(p, p->alerts.alerts[i].s);
+
+ if (PACKET_TEST_ACTION(p, ACTION_PASS)) {
+ /* Ok, reset the alert cnt to end in the previous of pass
+ * so we ignore the rest with less prio */
+ p->alerts.cnt = i;
+
+ /* if an stream/app-layer match we enforce the pass for the flow */
+ if ((p->flow != NULL) &&
+ (p->alerts.alerts[i].flags &
+ (PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_STREAM_MATCH)))
+ {
+ FlowLockSetNoPacketInspectionFlag(p->flow);
+ }
+ break;
+
+ /* if the signature wants to drop, check if the
+ * PACKET_ALERT_FLAG_DROP_FLOW flag is set. */
+ } else if ((PACKET_TEST_ACTION(p, ACTION_DROP)) &&
+ ((p->alerts.alerts[i].flags & PACKET_ALERT_FLAG_DROP_FLOW) ||
+ (s->flags & SIG_FLAG_APPLAYER))
+ && p->flow != NULL)
+ {
+ FLOWLOCK_WRLOCK(p->flow);
+ /* This will apply only on IPS mode (check StreamTcpPacket) */
+ p->flow->flags |= FLOW_ACTION_DROP;
+ FLOWLOCK_UNLOCK(p->flow);
+ }
+ }
+
+ /* Thresholding removes this alert */
+ if (res == 0 || res == 2) {
+ PacketAlertRemove(p, i);
+
+ if (p->alerts.cnt == 0)
+ break;
+ } else {
+ i++;
+ }
+ }
+
+ /* At this point, we should have all the new alerts. Now check the tag
+ * keyword context for sessions and hosts */
+ if (!(p->flags & PKT_PSEUDO_STREAM_END))
+ TagHandlePacket(de_ctx, det_ctx, p);
+}
+
+