aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/app-layer-template.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/suricata/src/app-layer-template.c')
-rw-r--r--framework/src/suricata/src/app-layer-template.c541
1 files changed, 0 insertions, 541 deletions
diff --git a/framework/src/suricata/src/app-layer-template.c b/framework/src/suricata/src/app-layer-template.c
deleted file mode 100644
index 5eafa67e..00000000
--- a/framework/src/suricata/src/app-layer-template.c
+++ /dev/null
@@ -1,541 +0,0 @@
-/* Copyright (C) 2015 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 Template application layer detector and parser for learning and
- * template pruposes.
- *
- * This template implements a simple application layer for something
- * like the echo protocol running on port 7.
- */
-
-#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-template.h"
-
-/* The default port to probe for echo traffic if not provided in the
- * configuration file. */
-#define TEMPLATE_DEFAULT_PORT "7"
-
-/* The minimum size for an echo message. For some protocols this might
- * be the size of a header. */
-#define TEMPLATE_MIN_FRAME_LEN 1
-
-/* Enum of app-layer events for an echo protocol. Normally you might
- * have events for errors in parsing data, like unexpected data being
- * received. For echo we'll make something up, and log an app-layer
- * level alert if an empty message is received.
- *
- * Example rule:
- *
- * alert template any any -> any any (msg:"SURCATA Template empty message"; \
- * app-layer-event:template.empty_message; sid:X; rev:Y;)
- */
-enum {
- TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE,
-};
-
-SCEnumCharMap template_decoder_event_table[] = {
- {"EMPTY_MESSAGE", TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE},
-};
-
-static TemplateTransaction *TemplateTxAlloc(TemplateState *echo)
-{
- TemplateTransaction *tx = SCCalloc(1, sizeof(TemplateTransaction));
- if (unlikely(tx == NULL)) {
- return NULL;
- }
-
- /* Increment the transaction ID on the state each time one is
- * allocated. */
- tx->tx_id = echo->transaction_max++;
-
- TAILQ_INSERT_TAIL(&echo->tx_list, tx, next);
-
- return tx;
-}
-
-static void TemplateTxFree(void *tx)
-{
- TemplateTransaction *templatetx = tx;
-
- if (templatetx->request_buffer != NULL) {
- SCFree(templatetx->request_buffer);
- }
-
- if (templatetx->response_buffer != NULL) {
- SCFree(templatetx->response_buffer);
- }
-
- AppLayerDecoderEventsFreeEvents(&templatetx->decoder_events);
-
- SCFree(tx);
-}
-
-static void *TemplateStateAlloc(void)
-{
- SCLogNotice("Allocating template state.");
- TemplateState *state = SCCalloc(1, sizeof(TemplateState));
- if (unlikely(state == NULL)) {
- return NULL;
- }
- TAILQ_INIT(&state->tx_list);
- return state;
-}
-
-static void TemplateStateFree(void *state)
-{
- TemplateState *template_state = state;
- TemplateTransaction *tx;
- SCLogNotice("Freeing template state.");
- while ((tx = TAILQ_FIRST(&template_state->tx_list)) != NULL) {
- TAILQ_REMOVE(&template_state->tx_list, tx, next);
- TemplateTxFree(tx);
- }
- SCFree(template_state);
-}
-
-/**
- * \brief Callback from the application layer to have a transaction freed.
- *
- * \param state a void pointer to the TemplateState object.
- * \param tx_id the transaction ID to free.
- */
-static void TemplateStateTxFree(void *state, uint64_t tx_id)
-{
- TemplateState *echo = state;
- TemplateTransaction *tx = NULL, *ttx;
-
- SCLogNotice("Freeing transaction %"PRIu64, tx_id);
-
- TAILQ_FOREACH_SAFE(tx, &echo->tx_list, next, ttx) {
-
- /* Continue if this is not the transaction we are looking
- * for. */
- if (tx->tx_id != tx_id) {
- continue;
- }
-
- /* Remove and free the transaction. */
- TAILQ_REMOVE(&echo->tx_list, tx, next);
- TemplateTxFree(tx);
- return;
- }
-
- SCLogNotice("Transaction %"PRIu64" not found.", tx_id);
-}
-
-static int TemplateStateGetEventInfo(const char *event_name, int *event_id,
- AppLayerEventType *event_type)
-{
- *event_id = SCMapEnumNameToValue(event_name, template_decoder_event_table);
- if (*event_id == -1) {
- SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
- "template enum map table.", event_name);
- /* This should be treated as fatal. */
- return -1;
- }
-
- *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
-
- return 0;
-}
-
-static AppLayerDecoderEvents *TemplateGetEvents(void *state, uint64_t tx_id)
-{
- TemplateState *template_state = state;
- TemplateTransaction *tx;
-
- TAILQ_FOREACH(tx, &template_state->tx_list, next) {
- if (tx->tx_id == tx_id) {
- return tx->decoder_events;
- }
- }
-
- return NULL;
-}
-
-static int TemplateHasEvents(void *state)
-{
- TemplateState *echo = state;
- return echo->events;
-}
-
-/**
- * \brief Probe the input to see if it looks like echo.
- *
- * \retval ALPROTO_TEMPLATE if it looks like echo, otherwise
- * ALPROTO_UNKNOWN.
- */
-static AppProto TemplateProbingParser(uint8_t *input, uint32_t input_len,
- uint32_t *offset)
-{
- /* Very simple test - if there is input, this is echo. */
- if (input_len >= TEMPLATE_MIN_FRAME_LEN) {
- SCLogNotice("Detected as ALPROTO_TEMPLATE.");
- return ALPROTO_TEMPLATE;
- }
-
- SCLogNotice("Protocol not detected as ALPROTO_TEMPLATE.");
- return ALPROTO_UNKNOWN;
-}
-
-static int TemplateParseRequest(Flow *f, void *state,
- AppLayerParserState *pstate, uint8_t *input, uint32_t input_len,
- void *local_data)
-{
- TemplateState *echo = state;
-
- SCLogNotice("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)) {
- return 0;
- }
-
- /* Probably don't want to create a transaction in this case
- * either. */
- if (input == NULL || input_len == 0) {
- return 0;
- }
-
- /* Normally you would parse out data here and store it in the
- * transaction object, but as this is echo, we'll just record the
- * request data. */
-
- /* Also, if this protocol may have a "protocol data unit" span
- * multiple chunks of data, which is always a possibility with
- * TCP, you may need to do some buffering here.
- *
- * For the sake of simplicity, buffering is left out here, but
- * even for an echo protocol we may want to buffer until a new
- * line is seen, assuming its text based.
- */
-
- /* Allocate a transaction.
- *
- * But note that if a "protocol data unit" is not received in one
- * chunk of data, and the buffering is done on the transaction, we
- * may need to look for the transaction that this newly recieved
- * data belongs to.
- */
- TemplateTransaction *tx = TemplateTxAlloc(echo);
- if (unlikely(tx == NULL)) {
- SCLogNotice("Failed to allocate new Template tx.");
- goto end;
- }
- SCLogNotice("Allocated Template tx %"PRIu64".", tx->tx_id);
-
- /* Make a copy of the request. */
- tx->request_buffer = SCCalloc(1, input_len);
- if (unlikely(tx->request_buffer == NULL)) {
- goto end;
- }
- memcpy(tx->request_buffer, input, input_len);
- tx->request_buffer_len = input_len;
-
- /* Here we check for an empty message and create an app-layer
- * event. */
- if ((input_len == 1 && tx->request_buffer[0] == '\n') ||
- (input_len == 2 && tx->request_buffer[0] == '\r')) {
- SCLogNotice("Creating event for empty message.");
- AppLayerDecoderEventsSetEventRaw(&tx->decoder_events,
- TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE);
- echo->events++;
- }
-
-end:
- return 0;
-}
-
-static int TemplateParseResponse(Flow *f, void *state, AppLayerParserState *pstate,
- uint8_t *input, uint32_t input_len, void *local_data)
-{
- TemplateState *echo = state;
- TemplateTransaction *tx = NULL, *ttx;;
-
- SCLogNotice("Parsing Template response.");
-
- /* Likely connection closed, we can just return here. */
- if ((input == NULL || input_len == 0) &&
- AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
- return 0;
- }
-
- /* Probably don't want to create a transaction in this case
- * either. */
- if (input == NULL || input_len == 0) {
- return 0;
- }
-
- /* Look up the existing transaction for this response. In the case
- * of echo, it will be the most recent transaction on the
- * TemplateState object. */
-
- /* We should just grab the last transaction, but this is to
- * illustrate how you might traverse the transaction list to find
- * the transaction associated with this response. */
- TAILQ_FOREACH(ttx, &echo->tx_list, next) {
- tx = ttx;
- }
-
- if (tx == NULL) {
- SCLogNotice("Failed to find transaction for response on echo state %p.",
- echo);
- goto end;
- }
-
- SCLogNotice("Found transaction %"PRIu64" for response on echo state %p.",
- tx->tx_id, echo);
-
- /* If the protocol requires multiple chunks of data to complete, you may
- * run into the case where you have existing response data.
- *
- * In this case, we just log that there is existing data and free it. But
- * you might want to realloc the buffer and append the data.
- */
- if (tx->response_buffer != NULL) {
- SCLogNotice("WARNING: Transaction already has response data, "
- "existing data will be overwritten.");
- SCFree(tx->response_buffer);
- }
-
- /* Make a copy of the response. */
- tx->response_buffer = SCCalloc(1, input_len);
- if (unlikely(tx->response_buffer == NULL)) {
- goto end;
- }
- memcpy(tx->response_buffer, input, input_len);
- tx->response_buffer_len = input_len;
-
- /* Set the response_done flag for transaction state checking in
- * TemplateGetStateProgress(). */
- tx->response_done = 1;
-
-end:
- return 0;
-}
-
-static uint64_t TemplateGetTxCnt(void *state)
-{
- TemplateState *echo = state;
- SCLogNotice("Current tx count is %"PRIu64".", echo->transaction_max);
- return echo->transaction_max;
-}
-
-static void *TemplateGetTx(void *state, uint64_t tx_id)
-{
- TemplateState *echo = state;
- TemplateTransaction *tx;
-
- SCLogNotice("Requested tx ID %"PRIu64".", tx_id);
-
- TAILQ_FOREACH(tx, &echo->tx_list, next) {
- if (tx->tx_id == tx_id) {
- SCLogNotice("Transaction %"PRIu64" found, returning tx object %p.",
- tx_id, tx);
- return tx;
- }
- }
-
- SCLogNotice("Transaction ID %"PRIu64" not found.", tx_id);
- return NULL;
-}
-
-/**
- * \brief Called by the application layer.
- *
- * In most cases 1 can be returned here.
- */
-static int TemplateGetAlstateProgressCompletionStatus(uint8_t direction) {
- return 1;
-}
-
-/**
- * \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 TemplateGetStateProgress(void *tx, uint8_t direction)
-{
- TemplateTransaction *echotx = tx;
-
- SCLogNotice("Transaction progress requested for tx ID %"PRIu64
- ", direction=0x%02x", echotx->tx_id, direction);
-
- if (direction & STREAM_TOCLIENT && echotx->response_done) {
- return 1;
- }
- else if (direction & STREAM_TOSERVER) {
- /* For echo, just the existence of the transaction means the
- * request is done. */
- return 1;
- }
-
- return 0;
-}
-
-/**
- * \brief ???
- */
-static DetectEngineState *TemplateGetTxDetectState(void *vtx)
-{
- TemplateTransaction *tx = vtx;
- return tx->de_state;
-}
-
-/**
- * \brief ???
- */
-static int TemplateSetTxDetectState(void *state, void *vtx,
- DetectEngineState *s)
-{
- TemplateTransaction *tx = vtx;
- tx->de_state = s;
- return 0;
-}
-
-void RegisterTemplateParsers(void)
-{
- char *proto_name = "template";
-
- /* TEMPLATE_START_REMOVE */
- if (ConfGetNode("app-layer.protocols.template") == NULL) {
- return;
- }
- /* TEMPLATE_END_REMOVE */
-
- /* Check if Template TCP detection is enabled. If it does not exist in
- * the configuration file then it will be enabled by default. */
- if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
-
- SCLogNotice("Template TCP protocol detection enabled.");
-
- AppLayerProtoDetectRegisterProtocol(ALPROTO_TEMPLATE, proto_name);
-
- if (RunmodeIsUnittests()) {
-
- SCLogNotice("Unittest mode, registeringd default configuration.");
- AppLayerProtoDetectPPRegister(IPPROTO_TCP, TEMPLATE_DEFAULT_PORT,
- ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN, STREAM_TOSERVER,
- TemplateProbingParser);
-
- }
- else {
-
- if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP,
- proto_name, ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN,
- TemplateProbingParser)) {
- SCLogNotice("No echo app-layer configuration, enabling echo"
- " detection TCP detection on port %s.",
- TEMPLATE_DEFAULT_PORT);
- AppLayerProtoDetectPPRegister(IPPROTO_TCP,
- TEMPLATE_DEFAULT_PORT, ALPROTO_TEMPLATE, 0,
- TEMPLATE_MIN_FRAME_LEN, STREAM_TOSERVER,
- TemplateProbingParser);
- }
-
- }
-
- }
-
- else {
- SCLogNotice("Protocol detecter and parser disabled for Template.");
- return;
- }
-
- if (AppLayerParserConfParserEnabled("udp", proto_name)) {
-
- SCLogNotice("Registering Template protocol parser.");
-
- /* Register functions for state allocation and freeing. A
- * state is allocated for every new Template flow. */
- AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_TEMPLATE,
- TemplateStateAlloc, TemplateStateFree);
-
- /* Register request parser for parsing frame from server to client. */
- AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEMPLATE,
- STREAM_TOSERVER, TemplateParseRequest);
-
- /* Register response parser for parsing frames from server to client. */
- AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEMPLATE,
- STREAM_TOCLIENT, TemplateParseResponse);
-
- /* Register a function to be called by the application layer
- * when a transaction is to be freed. */
- AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_TEMPLATE,
- TemplateStateTxFree);
-
- /* Register a function to return the current transaction count. */
- AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TEMPLATE,
- TemplateGetTxCnt);
-
- /* Transaction handling. */
- AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP,
- ALPROTO_TEMPLATE, TemplateGetAlstateProgressCompletionStatus);
- AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP,
- ALPROTO_TEMPLATE, TemplateGetStateProgress);
- AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_TEMPLATE,
- TemplateGetTx);
-
- /* Application layer event handling. */
- AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_TEMPLATE,
- TemplateHasEvents);
-
- /* What is this being registered for? */
- AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_TEMPLATE,
- NULL, TemplateGetTxDetectState, TemplateSetTxDetectState);
-
- AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_TEMPLATE,
- TemplateStateGetEventInfo);
- AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_TEMPLATE,
- TemplateGetEvents);
- }
- else {
- SCLogNotice("Template protocol parsing disabled.");
- }
-
-#ifdef UNITTESTS
- AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_TEMPLATE,
- TemplateParserRegisterTests);
-#endif
-}
-
-#ifdef UNITTESTS
-#endif
-
-void TemplateParserRegisterTests(void)
-{
-#ifdef UNITTESTS
-#endif
-}