/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 | } |