You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
suricata/src/app-layer-tftp.c

230 lines
7.8 KiB
C

/* Copyright (C) 2017-2024 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 "app-layer.h"
#include "app-layer-detect-proto.h"
#include "app-layer-parser.h"
#include "app-layer-tftp.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 SCTftpStateAlloc();
}
static void TFTPStateFree(void *state)
{
SCTftpStateFree(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)
{
SCTftpStateTxFree(state, tx_id);
}
static int TFTPStateGetEventInfo(
const char *event_name, uint8_t *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(
const 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) &&
SCAppLayerParserStateIssetFlag(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);
}
int64_t res = SCTftpParseRequest(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 SCTftpGetTxCnt(state);
}
static void *TFTPGetTx(void *state, uint64_t tx_id)
{
return SCTftpGetTx(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 (SCAppLayerProtoDetectConfProtoDetectionEnabled("udp", proto_name)) {
SCLogDebug("TFTP UDP protocol detection enabled.");
AppLayerProtoDetectRegisterProtocol(ALPROTO_TFTP, proto_name);
if (RunmodeIsUnittests()) {
SCLogDebug("Unittest mode, registering default configuration.");
SCAppLayerProtoDetectPPRegister(IPPROTO_UDP, TFTP_DEFAULT_PORT, ALPROTO_TFTP, 0,
TFTP_MIN_FRAME_LEN, STREAM_TOSERVER, TFTPProbingParser, TFTPProbingParser);
} else {
if (!SCAppLayerProtoDetectPPParseConfPorts("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);
SCAppLayerProtoDetectPPRegister(IPPROTO_UDP, TFTP_DEFAULT_PORT, ALPROTO_TFTP, 0,
TFTP_MIN_FRAME_LEN, STREAM_TOSERVER, TFTPProbingParser, TFTPProbingParser);
}
}
SCAppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_TFTP);
} else {
SCLogDebug("Protocol detector and parser disabled for TFTP.");
return;
}
if (SCAppLayerParserConfParserEnabled("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, SCTftpGetTxData);
AppLayerParserRegisterStateDataFunc(IPPROTO_UDP, ALPROTO_TFTP, SCTftpGetStateData);
} else {
SCLogDebug("TFTP protocol parsing disabled.");
}
}