Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/detect-ftp-dynamic-port.c
Line
Count
Source
1
/* Copyright (C) 2025 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
/**
19
 *
20
 * \author Jeff Lucovsky <jlucovsky@oisf.net>
21
 *
22
 * Implements the ftp.dynamic_port sticky buffer
23
 *
24
 */
25
26
#include "suricata-common.h"
27
#include "detect.h"
28
29
#include "detect-parse.h"
30
#include "detect-engine.h"
31
#include "detect-engine-mpm.h"
32
#include "detect-engine-prefilter.h"
33
#include "detect-engine-uint.h"
34
#include "detect-content.h"
35
36
#include "flow.h"
37
38
#include "util-debug.h"
39
40
#include "app-layer.h"
41
#include "app-layer-ftp.h"
42
43
#include "detect-ftp-dynamic-port.h"
44
45
79
#define KEYWORD_NAME "ftp.dynamic_port"
46
79
#define KEYWORD_DOC  "ftp-keywords.html#ftp-dynamic_port"
47
316
#define BUFFER_NAME  "ftp.dynamic_port"
48
79
#define BUFFER_DESC  "ftp dynamic_port"
49
50
static int g_ftp_dynport_buffer_id = 0;
51
52
static DetectU16Data *DetectFtpDynamicPortParse(const char *rawstr)
53
62
{
54
62
    return SCDetectU16Parse(rawstr);
55
62
}
56
57
static void DetectFtpDynamicPortFree(DetectEngineCtx *de_ctx, void *ptr)
58
57
{
59
57
    SCDetectU16Free(ptr);
60
57
}
61
62
static int DetectFtpDynamicPortSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
63
64
{
64
64
    if (SCDetectSignatureSetAppProto(s, ALPROTO_FTP) < 0)
65
2
        return -1;
66
67
62
    DetectU16Data *fdp = DetectFtpDynamicPortParse(str);
68
62
    if (fdp == NULL) {
69
5
        SCLogError("parsing dynamic port from \"%s\" failed", str);
70
5
        return -1;
71
5
    }
72
73
57
    SCLogDebug("low %u hi %u", fdp->arg1, fdp->arg2);
74
57
    if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_FTP_DYNPORT, (SigMatchCtx *)fdp,
75
57
                g_ftp_dynport_buffer_id) == NULL) {
76
0
        DetectFtpDynamicPortFree(de_ctx, fdp);
77
0
        return -1;
78
0
    }
79
57
    return 0;
80
57
}
81
82
static int DetectFtpDynamicPortMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags,
83
        void *state, void *txv, const Signature *s, const SigMatchCtx *ctx)
84
317
{
85
317
    SCEnter();
86
87
317
    FTPTransaction *tx = (FTPTransaction *)txv;
88
317
    if (tx->command_descriptor.command_code == FTP_COMMAND_UNKNOWN)
89
11
        return 0;
90
306
    if (tx->dyn_port == 0)
91
241
        return 0;
92
93
65
    const DetectU16Data *ftpd = (const DetectU16Data *)ctx;
94
95
65
    SCLogDebug("Checking for match between rule value(s) %u, %u with actual value %d", ftpd->arg1,
96
65
            ftpd->arg2, tx->dyn_port);
97
65
    return DetectU16Match(tx->dyn_port, ftpd);
98
306
}
99
100
void DetectFtpDynamicPortRegister(void)
101
79
{
102
    /* ftp.dynamic_port sticky buffer */
103
79
    sigmatch_table[DETECT_FTP_DYNPORT].name = KEYWORD_NAME;
104
79
    sigmatch_table[DETECT_FTP_DYNPORT].desc = "match on the FTP dynamic_port buffer";
105
79
    sigmatch_table[DETECT_FTP_DYNPORT].url = "/rules/" KEYWORD_DOC;
106
79
    sigmatch_table[DETECT_FTP_DYNPORT].Setup = DetectFtpDynamicPortSetup;
107
79
    sigmatch_table[DETECT_FTP_DYNPORT].Free = DetectFtpDynamicPortFree;
108
79
    sigmatch_table[DETECT_FTP_DYNPORT].flags = SIGMATCH_SUPPORT_FIREWALL;
109
79
    sigmatch_table[DETECT_FTP_DYNPORT].AppLayerTxMatch = DetectFtpDynamicPortMatch;
110
111
79
    DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_FTP, SIG_FLAG_TOCLIENT,
112
79
            FTP_STATE_FINISHED, DetectEngineInspectGenericList, NULL);
113
114
79
    DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_FTP, SIG_FLAG_TOSERVER,
115
79
            FTP_STATE_FINISHED, DetectEngineInspectGenericList, NULL);
116
117
79
    DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC);
118
119
79
    g_ftp_dynport_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
120
121
79
    SCLogDebug("registering " BUFFER_NAME " rule option");
122
79
}