]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect/ftp: Add ftp.dynamic_port keyword
authorJeff Lucovsky <jlucovsky@oisf.net>
Thu, 24 Apr 2025 12:46:13 +0000 (08:46 -0400)
committerVictor Julien <victor@inliniac.net>
Fri, 25 Apr 2025 07:51:46 +0000 (09:51 +0200)
Issue: 7504

Add implementation of the ftp.dynamic_port rule keyword. The
implementation uses the U16 integer matching/parsing and thus supports
the comparison operations such as <, >, <=, >=, !, !=, and range (-).

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

index ec169c585f3671afce53e17495d1eb5d0cad7634..19f8557b39f00a4e2bd8910f42cce16d515b6375 100755 (executable)
@@ -168,6 +168,7 @@ noinst_HEADERS = \
        detect-ftpdata.h \
        detect-ftp-command.h \
        detect-ftp-command-data.h \
+       detect-ftp-dynamic-port.h \
        detect-ftp-reply.h \
        detect-geoip.h \
        detect-gid.h \
@@ -754,6 +755,7 @@ libsuricata_c_a_SOURCES = \
        detect-ftpdata.c \
        detect-ftp-command.c \
        detect-ftp-command-data.c \
+       detect-ftp-dynamic-port.c \
        detect-ftp-reply.c \
        detect-geoip.c \
        detect-gid.c \
index 8a5710be5096dd48ded44ca7a2c88fd6d5c5664a..9038c5fdffeec3182c1786d75a9d194e6cda52c3 100644 (file)
 #include "detect-requires.h"
 #include "detect-tcp-window.h"
 #include "detect-ftpbounce.h"
+#include "detect-ftp-dynamic-port.h"
 #include "detect-isdataat.h"
 #include "detect-id.h"
 #include "detect-rpc.h"
@@ -633,6 +634,7 @@ void SigTableSetup(void)
     DetectRpcRegister();
     DetectFtpbounceRegister();
     DetectFtpdataRegister();
+    DetectFtpDynamicPortRegister();
     DetectIsdataatRegister();
     DetectIdRegister();
     DetectDsizeRegister();
index d67d57e0ced6bc40a97dc7e46044600e08b71c1f..a2ba40e74947e723c784733e99aff276c53d6460 100644 (file)
@@ -104,6 +104,7 @@ enum DetectKeywordId {
     DETECT_GEOIP,
     DETECT_IPPROTO,
     DETECT_FTPBOUNCE,
+    DETECT_FTP_DYNPORT,
     DETECT_ID,
     DETECT_RPC,
     DETECT_NOALERT,
diff --git a/src/detect-ftp-dynamic-port.c b/src/detect-ftp-dynamic-port.c
new file mode 100644 (file)
index 0000000..e3f7c0e
--- /dev/null
@@ -0,0 +1,117 @@
+/* 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.dynamic_port sticky buffer
+ *
+ */
+
+#include "suricata-common.h"
+#include "detect.h"
+
+#include "detect-parse.h"
+#include "detect-engine.h"
+#include "detect-engine-mpm.h"
+#include "detect-engine-prefilter.h"
+#include "detect-engine-uint.h"
+#include "detect-content.h"
+
+#include "flow.h"
+
+#include "util-debug.h"
+
+#include "app-layer.h"
+#include "app-layer-ftp.h"
+
+#include "detect-ftp-dynamic-port.h"
+
+#define KEYWORD_NAME "ftp.dynamic_port"
+#define KEYWORD_DOC  "ftp-keywords.html#ftp-dynamic_port"
+#define BUFFER_NAME  "ftp.dynamic_port"
+#define BUFFER_DESC  "ftp dynamic_port"
+
+static int g_ftp_dynport_buffer_id = 0;
+
+static DetectU16Data *DetectFtpDynamicPortParse(const char *rawstr)
+{
+    return SCDetectU16Parse(rawstr);
+}
+
+static void DetectFtpDynamicPortFree(DetectEngineCtx *de_ctx, void *ptr)
+{
+    SCDetectU16Free(ptr);
+}
+
+static int DetectFtpDynamicPortSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
+{
+    if (DetectSignatureSetAppProto(s, ALPROTO_FTP) < 0)
+        return -1;
+
+    DetectU16Data *fdp = DetectFtpDynamicPortParse(str);
+    if (fdp == NULL) {
+        SCLogError("parsing dynamic port from \"%s\" failed", str);
+        return -1;
+    }
+
+    SCLogDebug("low %u hi %u", fdp->arg1, fdp->arg2);
+    if (SigMatchAppendSMToList(de_ctx, s, DETECT_FTP_DYNPORT, (SigMatchCtx *)fdp,
+                g_ftp_dynport_buffer_id) == NULL) {
+        DetectFtpDynamicPortFree(de_ctx, fdp);
+        return -1;
+    }
+    return 0;
+}
+
+static int DetectFtpDynamicPortMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags,
+        void *state, void *txv, const Signature *s, const SigMatchCtx *ctx)
+{
+    SCEnter();
+
+    FTPTransaction *tx = (FTPTransaction *)txv;
+    if (tx->command_descriptor.command_code == FTP_COMMAND_UNKNOWN)
+        return 0;
+
+    const DetectU16Data *ftpd = (const DetectU16Data *)ctx;
+
+    SCLogDebug("Checking for match between rule value(s) %u, %u with actual value %d", ftpd->arg1,
+            ftpd->arg2, tx->dyn_port);
+    return DetectU16Match(tx->dyn_port, ftpd);
+}
+
+void DetectFtpDynamicPortRegister(void)
+{
+    /* ftp.dynamic_port sticky buffer */
+    sigmatch_table[DETECT_FTP_DYNPORT].name = KEYWORD_NAME;
+    sigmatch_table[DETECT_FTP_DYNPORT].desc = "match on the FTP dynamic_port buffer";
+    sigmatch_table[DETECT_FTP_DYNPORT].url = "/rules/" KEYWORD_DOC;
+    sigmatch_table[DETECT_FTP_DYNPORT].Setup = DetectFtpDynamicPortSetup;
+    sigmatch_table[DETECT_FTP_DYNPORT].Free = DetectFtpDynamicPortFree;
+    sigmatch_table[DETECT_FTP_DYNPORT].AppLayerTxMatch = DetectFtpDynamicPortMatch;
+
+    DetectAppLayerInspectEngineRegister(
+            BUFFER_NAME, ALPROTO_FTP, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL);
+
+    DetectAppLayerInspectEngineRegister(
+            BUFFER_NAME, ALPROTO_FTP, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL);
+
+    g_ftp_dynport_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
+
+    SCLogDebug("registering " BUFFER_NAME " rule option");
+}
diff --git a/src/detect-ftp-dynamic-port.h b/src/detect-ftp-dynamic-port.h
new file mode 100644 (file)
index 0000000..b0f42a8
--- /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_DYN_PORT_H
+#define SURICATA_DETECT_FTP_DYN_PORT_H
+
+void DetectFtpDynamicPortRegister(void);
+
+#endif /* SURICATA_DETECT_FTP_DYN_PORT_H */