summaryrefslogtreecommitdiffstats
path: root/src/app-layer-tftp.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:39:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:39:49 +0000
commita0aa2307322cd47bbf416810ac0292925e03be87 (patch)
tree37076262a026c4b48c8a0e84f44ff9187556ca35 /src/app-layer-tftp.c
parentInitial commit. (diff)
downloadsuricata-a0aa2307322cd47bbf416810ac0292925e03be87.tar.xz
suricata-a0aa2307322cd47bbf416810ac0292925e03be87.zip
Adding upstream version 1:7.0.3.upstream/1%7.0.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/app-layer-tftp.c')
-rw-r--r--src/app-layer-tftp.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/src/app-layer-tftp.c b/src/app-layer-tftp.c
new file mode 100644
index 0000000..73dc52a
--- /dev/null
+++ b/src/app-layer-tftp.c
@@ -0,0 +1,242 @@
+/* Copyright (C) 2017-2021 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 Clément Galland <clement.galland@epita.fr>
+ *
+ * Parser for NTP application layer running on UDP port 69.
+ */
+
+
+#include "suricata-common.h"
+#include "suricata.h"
+#include "stream.h"
+#include "conf.h"
+
+#include "util-unittest.h"
+
+#include "app-layer.h"
+#include "app-layer-detect-proto.h"
+#include "app-layer-parser.h"
+
+#include "app-layer-tftp.h"
+#include "rust.h"
+
+/* The default port to probe if not provided in the configuration file. */
+#define TFTP_DEFAULT_PORT "69"
+
+/* The minimum size for an message. For some protocols this might
+ * be the size of a header. */
+#define TFTP_MIN_FRAME_LEN 4
+
+static void *TFTPStateAlloc(void *orig_state, AppProto proto_orig)
+{
+ return rs_tftp_state_alloc();
+}
+
+static void TFTPStateFree(void *state)
+{
+ rs_tftp_state_free(state);
+}
+
+/**
+ * \brief Callback from the application layer to have a transaction freed.
+ *
+ * \param state a void pointer to the TFTPState object.
+ * \param tx_id the transaction ID to free.
+ */
+static void TFTPStateTxFree(void *state, uint64_t tx_id)
+{
+ rs_tftp_state_tx_free(state, tx_id);
+}
+
+static int TFTPStateGetEventInfo(const char *event_name, int *event_id,
+ AppLayerEventType *event_type)
+{
+ return -1;
+}
+
+/**
+ * \brief Probe the input to see if it looks like tftp.
+ *
+ * \retval ALPROTO_TFTP if it looks like tftp, otherwise
+ * ALPROTO_UNKNOWN.
+ */
+static AppProto TFTPProbingParser(Flow *f, uint8_t direction,
+ const uint8_t *input, uint32_t input_len, uint8_t *rdir)
+{
+ /* Very simple test - if there is input, this is tftp.
+ * Also check if it's starting by a zero */
+ if (input_len >= TFTP_MIN_FRAME_LEN && *input == 0) {
+ SCLogDebug("Detected as ALPROTO_TFTP.");
+ return ALPROTO_TFTP;
+ }
+
+ SCLogDebug("Protocol not detected as ALPROTO_TFTP.");
+ return ALPROTO_UNKNOWN;
+}
+
+static AppLayerResult TFTPParseRequest(Flow *f, void *state, AppLayerParserState *pstate,
+ StreamSlice stream_slice, void *local_data)
+{
+ const uint8_t *input = StreamSliceGetData(&stream_slice);
+ uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
+
+ SCLogDebug("Parsing tftp request: len=%" PRIu32, input_len);
+
+ /* Likely connection closed, we can just return here. */
+ if ((input == NULL || input_len == 0) &&
+ AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) {
+ SCReturnStruct(APP_LAYER_OK);
+ }
+
+ /* Probably don't want to create a transaction in this case
+ * either. */
+ if (input == NULL || input_len == 0) {
+ SCReturnStruct(APP_LAYER_OK);
+ }
+
+ int res = rs_tftp_request(state, input, input_len);
+ if (res < 0) {
+ SCReturnStruct(APP_LAYER_ERROR);
+ }
+ SCReturnStruct(APP_LAYER_OK);
+}
+
+/**
+ * \brief Response parsing is not implemented
+ */
+static AppLayerResult TFTPParseResponse(Flow *f, void *state, AppLayerParserState *pstate,
+ StreamSlice stream_slice, void *local_data)
+{
+ SCReturnStruct(APP_LAYER_OK);
+}
+
+static uint64_t TFTPGetTxCnt(void *state)
+{
+ return rs_tftp_get_tx_cnt(state);
+}
+
+static void *TFTPGetTx(void *state, uint64_t tx_id)
+{
+ return rs_tftp_get_tx(state, tx_id);
+}
+
+/**
+ * \brief Return the state of a transaction in a given direction.
+ *
+ * In the case of the tftp protocol, the existence of a transaction
+ * means that the request is done. However, some protocols that may
+ * need multiple chunks of data to complete the request may need more
+ * than just the existence of a transaction for the request to be
+ * considered complete.
+ *
+ * For the response to be considered done, the response for a request
+ * needs to be seen. The response_done flag is set on response for
+ * checking here.
+ */
+static int TFTPGetStateProgress(void *tx, uint8_t direction)
+{
+ return 1;
+}
+
+void RegisterTFTPParsers(void)
+{
+ const char *proto_name = "tftp";
+
+ /* Check if TFTP UDP detection is enabled. If it does not exist in
+ * the configuration file then it will be enabled by default. */
+ if (AppLayerProtoDetectConfProtoDetectionEnabled("udp", proto_name)) {
+
+ SCLogDebug("TFTP UDP protocol detection enabled.");
+
+ AppLayerProtoDetectRegisterProtocol(ALPROTO_TFTP, proto_name);
+
+ if (RunmodeIsUnittests()) {
+ SCLogDebug("Unittest mode, registering default configuration.");
+ AppLayerProtoDetectPPRegister(IPPROTO_UDP, TFTP_DEFAULT_PORT,
+ ALPROTO_TFTP, 0, TFTP_MIN_FRAME_LEN,
+ STREAM_TOSERVER, TFTPProbingParser,
+ TFTPProbingParser);
+ } else {
+ if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP,
+ proto_name, ALPROTO_TFTP,
+ 0, TFTP_MIN_FRAME_LEN,
+ TFTPProbingParser, TFTPProbingParser)) {
+ SCLogDebug("No tftp app-layer configuration, enabling tftp"
+ " detection UDP detection on port %s.",
+ TFTP_DEFAULT_PORT);
+ AppLayerProtoDetectPPRegister(IPPROTO_UDP,
+ TFTP_DEFAULT_PORT, ALPROTO_TFTP,
+ 0, TFTP_MIN_FRAME_LEN,
+ STREAM_TOSERVER,TFTPProbingParser,
+ TFTPProbingParser);
+ }
+ }
+ } else {
+ SCLogDebug("Protocol detector and parser disabled for TFTP.");
+ return;
+ }
+
+ if (AppLayerParserConfParserEnabled("udp", proto_name)) {
+
+ SCLogDebug("Registering TFTP protocol parser.");
+
+ /* Register functions for state allocation and freeing. A
+ * state is allocated for every new TFTP flow. */
+ AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_TFTP,
+ TFTPStateAlloc, TFTPStateFree);
+
+ /* Register request parser for parsing frame from server to client. */
+ AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_TFTP,
+ STREAM_TOSERVER, TFTPParseRequest);
+
+ /* Register response parser for parsing frames from server to client. */
+ AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_TFTP,
+ STREAM_TOCLIENT, TFTPParseResponse);
+
+ /* Register a function to be called by the application layer
+ * when a transaction is to be freed. */
+ AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_TFTP,
+ TFTPStateTxFree);
+
+ /* Register a function to return the current transaction count. */
+ AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_TFTP,
+ TFTPGetTxCnt);
+
+ /* Transaction handling. */
+ AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_TFTP, 1, 1);
+ AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP,
+ ALPROTO_TFTP,
+ TFTPGetStateProgress);
+ AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_TFTP,
+ TFTPGetTx);
+
+ AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_TFTP,
+ TFTPStateGetEventInfo);
+
+ AppLayerParserRegisterTxDataFunc(IPPROTO_UDP, ALPROTO_TFTP,
+ rs_tftp_get_tx_data);
+ AppLayerParserRegisterStateDataFunc(IPPROTO_UDP, ALPROTO_TFTP, rs_tftp_get_state_data);
+ }
+ else {
+ SCLogDebug("TFTP protocol parsing disabled.");
+ }
+}