mirror of https://github.com/OISF/suricata
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.
262 lines
8.7 KiB
C
262 lines
8.7 KiB
C
/* Copyright (C) 2017-2020 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 "stream.h"
|
|
#include "conf.h"
|
|
|
|
#include "util-unittest.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;
|
|
}
|
|
|
|
static AppLayerDecoderEvents *TFTPGetEvents(void *tx)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* \brief Probe the input to see if it looks like echo.
|
|
*
|
|
* \retval ALPROTO_TFTP if it looks like echo, 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, const uint8_t *input, uint32_t input_len,
|
|
void *local_data, const uint8_t flags)
|
|
{
|
|
SCLogDebug("Parsing echo 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,
|
|
const uint8_t *input, uint32_t input_len, void *local_data,
|
|
const uint8_t flags)
|
|
{
|
|
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 echo 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;
|
|
}
|
|
|
|
static DetectEngineState *TFTPGetTxDetectState(void *vtx)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static int TFTPSetTxDetectState(void *vtx,
|
|
DetectEngineState *s)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
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, registeringd 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 echo app-layer configuration, enabling echo"
|
|
" 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 detecter 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);
|
|
|
|
/* What is this being registered for? */
|
|
AppLayerParserRegisterDetectStateFuncs(IPPROTO_UDP, ALPROTO_TFTP,
|
|
TFTPGetTxDetectState,
|
|
TFTPSetTxDetectState);
|
|
|
|
AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_TFTP,
|
|
TFTPStateGetEventInfo);
|
|
AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_TFTP,
|
|
TFTPGetEvents);
|
|
|
|
AppLayerParserRegisterTxDataFunc(IPPROTO_UDP, ALPROTO_TFTP,
|
|
rs_tftp_get_tx_data);
|
|
}
|
|
else {
|
|
SCLogDebug("TFTP protocol parsing disabled.");
|
|
}
|
|
}
|