Coverage Report

Created: 2026-09-28 07:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata/src/app-layer-tftp.c
Line
Count
Source
1
/* Copyright (C) 2017-2024 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
 * \file
21
 *
22
 * \author Clément Galland <clement.galland@epita.fr>
23
 *
24
 * Parser for NTP application layer running on UDP port 69.
25
 */
26
27
28
#include "suricata-common.h"
29
#include "suricata.h"
30
31
#include "app-layer.h"
32
#include "app-layer-detect-proto.h"
33
#include "app-layer-parser.h"
34
35
#include "app-layer-tftp.h"
36
37
/* The default port to probe if not provided in the configuration file. */
38
81
#define TFTP_DEFAULT_PORT "69"
39
40
/* The minimum size for an message. For some protocols this might
41
 * be the size of a header. */
42
868
#define TFTP_MIN_FRAME_LEN 4
43
44
static void *TFTPStateAlloc(void *orig_state, AppProto proto_orig)
45
1.14k
{
46
1.14k
    return SCTftpStateAlloc();
47
1.14k
}
48
49
static void TFTPStateFree(void *state)
50
1.14k
{
51
1.14k
    SCTftpStateFree(state);
52
1.14k
}
53
54
/**
55
 * \brief Callback from the application layer to have a transaction freed.
56
 *
57
 * \param state a void pointer to the TFTPState object.
58
 * \param tx_id the transaction ID to free.
59
 */
60
static void TFTPStateTxFree(void *state, uint64_t tx_id)
61
696k
{
62
696k
    SCTftpStateTxFree(state, tx_id);
63
696k
}
64
65
static int TFTPStateGetEventInfo(
66
        const char *event_name, uint8_t *event_id, AppLayerEventType *event_type)
67
1
{
68
1
    return -1;
69
1
}
70
71
/**
72
 * \brief Probe the input to see if it looks like tftp.
73
 *
74
 * \retval ALPROTO_TFTP if it looks like tftp, otherwise
75
 *     ALPROTO_UNKNOWN.
76
 */
77
static AppProto TFTPProbingParser(
78
        const Flow *f, uint8_t direction, const uint8_t *input, uint32_t input_len, uint8_t *rdir)
79
353
{
80
    /* Very simple test - if there is input, this is tftp.
81
     * Also check if it's starting by a zero */
82
353
    if (input_len >= TFTP_MIN_FRAME_LEN && *input == 0) {
83
264
        SCLogDebug("Detected as ALPROTO_TFTP.");
84
264
        return ALPROTO_TFTP;
85
264
    }
86
87
89
    SCLogDebug("Protocol not detected as ALPROTO_TFTP.");
88
89
    return ALPROTO_UNKNOWN;
89
353
}
90
91
static AppLayerResult TFTPParseRequest(Flow *f, void *state, AppLayerParserState *pstate,
92
        StreamSlice stream_slice, void *local_data)
93
698k
{
94
698k
    const uint8_t *input = StreamSliceGetData(&stream_slice);
95
698k
    uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
96
97
698k
    SCLogDebug("Parsing tftp request: len=%" PRIu32, input_len);
98
99
    /* Likely connection closed, we can just return here. */
100
698k
    if ((input == NULL || input_len == 0) &&
101
0
            SCAppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) {
102
0
        SCReturnStruct(APP_LAYER_OK);
103
0
    }
104
105
    /* Probably don't want to create a transaction in this case
106
     * either. */
107
698k
    if (input == NULL || input_len == 0) {
108
0
        SCReturnStruct(APP_LAYER_OK);
109
0
    }
110
111
698k
    int64_t res = SCTftpParseRequest(state, input, input_len);
112
698k
    if (res < 0) {
113
1.25k
        SCReturnStruct(APP_LAYER_ERROR);
114
1.25k
    }
115
698k
    SCReturnStruct(APP_LAYER_OK);
116
698k
}
117
118
/**
119
 * \brief Response parsing is not implemented
120
 */
121
static AppLayerResult TFTPParseResponse(Flow *f, void *state, AppLayerParserState *pstate,
122
        StreamSlice stream_slice, void *local_data)
123
22.4k
{
124
22.4k
    SCReturnStruct(APP_LAYER_OK);
125
22.4k
}
126
127
static uint64_t TFTPGetTxCnt(void *state)
128
2.16M
{
129
2.16M
    return SCTftpGetTxCnt(state);
130
2.16M
}
131
132
static void *TFTPGetTx(void *state, uint64_t tx_id)
133
721k
{
134
721k
    return SCTftpGetTx(state, tx_id);
135
721k
}
136
137
/**
138
 * \brief Return the state of a transaction in a given direction.
139
 *
140
 * In the case of the tftp protocol, the existence of a transaction
141
 * means that the request is done. However, some protocols that may
142
 * need multiple chunks of data to complete the request may need more
143
 * than just the existence of a transaction for the request to be
144
 * considered complete.
145
 *
146
 * For the response to be considered done, the response for a request
147
 * needs to be seen.  The response_done flag is set on response for
148
 * checking here.
149
 */
150
static int TFTPGetStateProgress(void *tx, uint8_t direction)
151
1.44M
{
152
1.44M
    return 1;
153
1.44M
}
154
155
void RegisterTFTPParsers(void)
156
81
{
157
81
    const char *proto_name = "tftp";
158
159
    /* Check if TFTP UDP detection is enabled. If it does not exist in
160
     * the configuration file then it will be enabled by default. */
161
81
    if (SCAppLayerProtoDetectConfProtoDetectionEnabled("udp", proto_name)) {
162
163
81
        SCLogDebug("TFTP UDP protocol detection enabled.");
164
165
81
        AppLayerProtoDetectRegisterProtocol(ALPROTO_TFTP, proto_name);
166
167
81
        if (RunmodeIsUnittests()) {
168
0
            SCLogDebug("Unittest mode, registering default configuration.");
169
0
            SCAppLayerProtoDetectPPRegister(IPPROTO_UDP, TFTP_DEFAULT_PORT, ALPROTO_TFTP, 0,
170
0
                    TFTP_MIN_FRAME_LEN, STREAM_TOSERVER, TFTPProbingParser, TFTPProbingParser);
171
81
        } else {
172
81
            if (!SCAppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP, proto_name, ALPROTO_TFTP,
173
81
                        0, TFTP_MIN_FRAME_LEN, TFTPProbingParser, TFTPProbingParser)) {
174
81
                SCLogDebug("No tftp app-layer configuration, enabling tftp"
175
81
                           " detection UDP detection on port %s.",
176
81
                        TFTP_DEFAULT_PORT);
177
81
                SCAppLayerProtoDetectPPRegister(IPPROTO_UDP, TFTP_DEFAULT_PORT, ALPROTO_TFTP, 0,
178
81
                        TFTP_MIN_FRAME_LEN, STREAM_TOSERVER, TFTPProbingParser, TFTPProbingParser);
179
81
            }
180
81
        }
181
81
        SCAppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_TFTP);
182
81
    } else {
183
0
        SCLogDebug("Protocol detector and parser disabled for TFTP.");
184
0
        return;
185
0
    }
186
187
81
    if (SCAppLayerParserConfParserEnabled("udp", proto_name)) {
188
189
81
        SCLogDebug("Registering TFTP protocol parser.");
190
191
        /* Register functions for state allocation and freeing. A
192
         * state is allocated for every new TFTP flow. */
193
81
        AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_TFTP,
194
81
                                         TFTPStateAlloc, TFTPStateFree);
195
196
        /* Register request parser for parsing frame from server to client. */
197
81
        AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_TFTP,
198
81
                                     STREAM_TOSERVER, TFTPParseRequest);
199
200
        /* Register response parser for parsing frames from server to client. */
201
81
        AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_TFTP,
202
81
                                     STREAM_TOCLIENT, TFTPParseResponse);
203
204
        /* Register a function to be called by the application layer
205
         * when a transaction is to be freed. */
206
81
        AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_TFTP,
207
81
                                         TFTPStateTxFree);
208
209
        /* Register a function to return the current transaction count. */
210
81
        AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_TFTP,
211
81
                                       TFTPGetTxCnt);
212
213
        /* Transaction handling. */
214
81
        AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_TFTP, 1, 1);
215
81
        AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP,
216
81
                                                   ALPROTO_TFTP,
217
81
                                                   TFTPGetStateProgress);
218
81
        AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_TFTP,
219
81
                                    TFTPGetTx);
220
221
81
        AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_TFTP,
222
81
                                           TFTPStateGetEventInfo);
223
224
81
        AppLayerParserRegisterTxDataFunc(IPPROTO_UDP, ALPROTO_TFTP, SCTftpGetTxData);
225
81
        AppLayerParserRegisterStateDataFunc(IPPROTO_UDP, ALPROTO_TFTP, SCTftpGetStateData);
226
81
    } else {
227
0
        SCLogDebug("TFTP protocol parsing disabled.");
228
0
    }
229
81
}