/* 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 * * 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."); } }