]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect/ftp: Add ftp.mode command
authorJeff Lucovsky <jlucovsky@oisf.net>
Fri, 25 Apr 2025 14:47:47 +0000 (10:47 -0400)
committerVictor Julien <victor@inliniac.net>
Wed, 14 May 2025 05:35:28 +0000 (07:35 +0200)
Issue: 7505

This commit adds support for the ftp.mode keyword.

ftp.mode: active|passive

src/Makefile.am
src/detect-engine-register.c
src/detect-engine-register.h
src/detect-ftp-mode.c [new file with mode: 0644]
src/detect-ftp-mode.h [new file with mode: 0644]

index 8c4db1df660ce26d9ebbbb6398ebecca980fef40..47c123798ba81a0218686876712a06ba2f7ce67e 100755 (executable)
@@ -180,6 +180,7 @@ noinst_HEADERS = \
        detect-ftp-reply.h \
        detect-ftpbounce.h \
        detect-ftpdata.h \
+       detect-ftp-mode.h \
        detect-geoip.h \
        detect-gid.h \
        detect-hostbits.h \
@@ -770,6 +771,7 @@ libsuricata_c_a_SOURCES = \
        detect-ftp-reply.c \
        detect-ftpbounce.c \
        detect-ftpdata.c \
+       detect-ftp-mode.c \
        detect-geoip.c \
        detect-gid.c \
        detect-hostbits.c \
index 49d34ce5f9e506a43c0726fed05d243542648ffd..b60555d590938c372921343a83fa3b0427dbfb05 100644 (file)
 #include "detect-entropy.h"
 #include "detect-ftp-command-data.h"
 #include "detect-ftp-reply.h"
+#include "detect-ftp-mode.h"
 
 #include "detect-bypass.h"
 #include "detect-ftpdata.h"
@@ -726,6 +727,7 @@ void SigTableSetup(void)
     DetectFtpCommandRegister();
     DetectFtpCommandDataRegister();
     DetectFtpReplyRegister();
+    DetectFtpModeRegister();
 
     DetectBypassRegister();
     DetectConfigRegister();
index 1f714e4b46384db4212dff7797c33457c2ff8a1f..5f9053e77705c38b1fe6a50f74610cc41c6aa394 100644 (file)
@@ -331,6 +331,7 @@ enum DetectKeywordId {
     DETECT_FTP_COMMAND,
     DETECT_FTP_COMMAND_DATA,
     DETECT_FTP_REPLY,
+    DETECT_FTP_MODE,
 
     DETECT_VLAN_ID,
     DETECT_VLAN_LAYERS,
diff --git a/src/detect-ftp-mode.c b/src/detect-ftp-mode.c
new file mode 100644 (file)
index 0000000..1f4124e
--- /dev/null
@@ -0,0 +1,142 @@
+/* Copyright (C) 2025 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.
+ */
+
+/**
+ *
+ * \author Jeff Lucovsky <jlucovsky@oisf.net>
+ *
+ * Implements the ftp.mode sticky buffer
+ *
+ */
+
+#include "suricata-common.h"
+
+#include "detect.h"
+#include "detect-parse.h"
+#include "detect-engine.h"
+
+#include "rust.h"
+#include "flow.h"
+
+#include "util-debug.h"
+
+#include "app-layer.h"
+#include "app-layer-ftp.h"
+
+#include "detect-ftp-mode.h"
+
+#define KEYWORD_NAME "ftp.mode"
+#define KEYWORD_DOC  "ftp-keywords.html#ftp-mode"
+#define BUFFER_NAME  "ftp.mode"
+#define BUFFER_DESC  "ftp mode"
+
+static int g_ftp_mode_buffer_id = 0;
+
+/**
+ * \brief This function is used to check matches from the FTP App Layer Parser
+ *
+ * \param t pointer to thread vars
+ * \param det_ctx pointer to the pattern matcher thread
+ * \param p pointer to the current packet
+ * \param m pointer to the sigmatch
+ * \retval 0 no match
+ * \retval 1 match
+ */
+static int DetectFtpModeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state,
+        void *txv, const Signature *s, const SigMatchCtx *m)
+{
+    FTPTransaction *tx = (FTPTransaction *)txv;
+    if (tx->command_descriptor.command_code == FTP_COMMAND_UNKNOWN) {
+        return 0;
+    }
+    if (!tx->dyn_port) {
+        return 0;
+    }
+
+    const DetectFtpModeData *ftpmoded = (const DetectFtpModeData *)m;
+    return ftpmoded->active == tx->active;
+}
+
+/**
+ * \brief this function will free memory associated with DetectFtpModeData
+ *
+ * \param ptr pointer to DetectFtpModeData
+ */
+static void DetectFtpModeFree(DetectEngineCtx *de_ctx, void *ptr)
+{
+    SCFTPFreeModeData(ptr);
+}
+
+/**
+ * \brief This function is used to parse ftp.mode options passed via ftp.mode keyword
+ *
+ * \param str Pointer to the user provided ftp.mode options
+ *
+ * \retval  pointer to DetectFtpModeData on success
+ * \retval NULL on failure
+ */
+static DetectFtpModeData *DetectFtpModeParse(const char *optstr)
+{
+    DetectFtpModeData *ftpmoded = SCFTPParseMode(optstr);
+    if (unlikely(ftpmoded == NULL)) {
+        SCLogError("Invalid command value");
+        return NULL;
+    }
+
+    return ftpmoded;
+}
+
+static int DetectFtpModeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
+{
+    if (DetectSignatureSetAppProto(s, ALPROTO_FTP) != 0)
+        return -1;
+
+    DetectFtpModeData *ftpmoded = DetectFtpModeParse(str);
+    if (ftpmoded == NULL)
+        return -1;
+
+    if (SigMatchAppendSMToList(de_ctx, s, DETECT_FTP_MODE, (SigMatchCtx *)ftpmoded,
+                g_ftp_mode_buffer_id) == NULL) {
+        DetectFtpModeFree(de_ctx, ftpmoded);
+        return -1;
+    }
+
+    return 0;
+}
+
+void DetectFtpModeRegister(void)
+{
+    /* ftp.mode sticky buffer */
+    sigmatch_table[DETECT_FTP_MODE].name = KEYWORD_NAME;
+    sigmatch_table[DETECT_FTP_MODE].desc = "sticky buffer to match on the FTP mode buffer";
+    sigmatch_table[DETECT_FTP_MODE].url = "/rules/" KEYWORD_DOC;
+    sigmatch_table[DETECT_FTP_MODE].Setup = DetectFtpModeSetup;
+    sigmatch_table[DETECT_FTP_MODE].AppLayerTxMatch = DetectFtpModeMatch;
+    sigmatch_table[DETECT_FTP_MODE].Free = DetectFtpModeFree;
+
+    DetectAppLayerInspectEngineRegister(
+            BUFFER_NAME, ALPROTO_FTP, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL);
+
+    DetectAppLayerInspectEngineRegister(
+            BUFFER_NAME, ALPROTO_FTP, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL);
+
+    DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC);
+
+    g_ftp_mode_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
+
+    SCLogDebug("registering " BUFFER_NAME " rule option");
+}
diff --git a/src/detect-ftp-mode.h b/src/detect-ftp-mode.h
new file mode 100644 (file)
index 0000000..35f36ca
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2025 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.
+ */
+
+/**
+ * \file
+ *
+ * \author Jeff Lucovsky  <jlucovsky@oisf.net>
+ */
+
+#ifndef SURICATA_DETECT_FTP_MODE_H
+#define SURICATA_DETECT_FTP_MODE_H
+
+void DetectFtpModeRegister(void);
+
+#endif /* SURICATA_DETECT_FTP_MODE_H */