1 /* Copyright (C) 2015-2020 Open Information Security Foundation
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * TODO: Update \author in this file and app-layer-template.h.
20 * TODO: Implement your app-layer logic with unit tests.
21 * TODO: Remove SCLogNotice statements or convert to debug.
27 * \author FirstName LastName <yourname@domain>
29 * Template application layer detector and parser for learning and
32 * This template implements a simple application layer for something
33 * like the echo protocol running on port 7.
36 #include "suricata-common.h"
39 #include "app-layer-detect-proto.h"
40 #include "app-layer-parser.h"
41 #include "app-layer-template.h"
43 #include "util-unittest.h"
44 #include "util-validate.h"
46 /* The default port to probe for echo traffic if not provided in the
47 * configuration file. */
48 #define TEMPLATE_DEFAULT_PORT "7"
50 /* The minimum size for a message. For some protocols this might
51 * be the size of a header. */
52 #define TEMPLATE_MIN_FRAME_LEN 1
54 /* Enum of app-layer events for the protocol. Normally you might
55 * have events for errors in parsing data, like unexpected data being
56 * received. For template we'll make something up, and log an app-layer
57 * level alert if an empty message is received.
61 * alert template any any -> any any (msg:"SURICATA Template empty message"; \
62 * app-layer-event:template.empty_message; sid:X; rev:Y;)
65 TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE
,
68 SCEnumCharMap template_decoder_event_table
[] = {
69 {"EMPTY_MESSAGE", TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE
},
71 // event table must be NULL-terminated
75 static TemplateTransaction
*TemplateTxAlloc(TemplateState
*state
)
77 TemplateTransaction
*tx
= SCCalloc(1, sizeof(TemplateTransaction
));
78 if (unlikely(tx
== NULL
)) {
82 /* Increment the transaction ID on the state each time one is
84 tx
->tx_id
= state
->transaction_max
++;
86 TAILQ_INSERT_TAIL(&state
->tx_list
, tx
, next
);
91 static void TemplateTxFree(void *txv
)
93 TemplateTransaction
*tx
= txv
;
95 if (tx
->request_buffer
!= NULL
) {
96 SCFree(tx
->request_buffer
);
99 if (tx
->response_buffer
!= NULL
) {
100 SCFree(tx
->response_buffer
);
103 AppLayerDecoderEventsFreeEvents(&tx
->decoder_events
);
108 static void *TemplateStateAlloc(void *orig_state
, AppProto proto_orig
)
110 SCLogNotice("Allocating template state.");
111 TemplateState
*state
= SCCalloc(1, sizeof(TemplateState
));
112 if (unlikely(state
== NULL
)) {
115 TAILQ_INIT(&state
->tx_list
);
119 static void TemplateStateFree(void *state
)
121 TemplateState
*template_state
= state
;
122 TemplateTransaction
*tx
;
123 SCLogNotice("Freeing template state.");
124 while ((tx
= TAILQ_FIRST(&template_state
->tx_list
)) != NULL
) {
125 TAILQ_REMOVE(&template_state
->tx_list
, tx
, next
);
128 SCFree(template_state
);
132 * \brief Callback from the application layer to have a transaction freed.
134 * \param state a void pointer to the TemplateState object.
135 * \param tx_id the transaction ID to free.
137 static void TemplateStateTxFree(void *statev
, uint64_t tx_id
)
139 TemplateState
*state
= statev
;
140 TemplateTransaction
*tx
= NULL
, *ttx
;
142 SCLogNotice("Freeing transaction %"PRIu64
, tx_id
);
144 TAILQ_FOREACH_SAFE(tx
, &state
->tx_list
, next
, ttx
) {
146 /* Continue if this is not the transaction we are looking
148 if (tx
->tx_id
!= tx_id
) {
152 /* Remove and free the transaction. */
153 TAILQ_REMOVE(&state
->tx_list
, tx
, next
);
158 SCLogNotice("Transaction %"PRIu64
" not found.", tx_id
);
161 static int TemplateStateGetEventInfo(const char *event_name
, int *event_id
,
162 AppLayerEventType
*event_type
)
164 *event_id
= SCMapEnumNameToValue(event_name
, template_decoder_event_table
);
165 if (*event_id
== -1) {
166 SCLogError(SC_ERR_INVALID_ENUM_MAP
, "event \"%s\" not present in "
167 "template enum map table.", event_name
);
168 /* This should be treated as fatal. */
172 *event_type
= APP_LAYER_EVENT_TYPE_TRANSACTION
;
177 static int TemplateStateGetEventInfoById(int event_id
, const char **event_name
,
178 AppLayerEventType
*event_type
)
180 *event_name
= SCMapEnumValueToName(event_id
, template_decoder_event_table
);
181 if (*event_name
== NULL
) {
182 SCLogError(SC_ERR_INVALID_ENUM_MAP
, "event \"%d\" not present in "
183 "template enum map table.", event_id
);
184 /* This should be treated as fatal. */
188 *event_type
= APP_LAYER_EVENT_TYPE_TRANSACTION
;
193 static AppLayerDecoderEvents
*TemplateGetEvents(void *tx
)
195 return ((TemplateTransaction
*)tx
)->decoder_events
;
199 * \brief Probe the input to server to see if it looks like template.
201 * \retval ALPROTO_TEMPLATE if it looks like template,
202 * ALPROTO_FAILED, if it is clearly not ALPROTO_TEMPLATE,
203 * otherwise ALPROTO_UNKNOWN.
205 static AppProto
TemplateProbingParserTs(Flow
*f
, uint8_t direction
,
206 const uint8_t *input
, uint32_t input_len
, uint8_t *rdir
)
208 /* Very simple test - if there is input, this is template. */
209 if (input_len
>= TEMPLATE_MIN_FRAME_LEN
) {
210 SCLogNotice("Detected as ALPROTO_TEMPLATE.");
211 return ALPROTO_TEMPLATE
;
214 SCLogNotice("Protocol not detected as ALPROTO_TEMPLATE.");
215 return ALPROTO_UNKNOWN
;
219 * \brief Probe the input to client to see if it looks like template.
220 * TemplateProbingParserTs can be used instead if the protocol
223 * \retval ALPROTO_TEMPLATE if it looks like template,
224 * ALPROTO_FAILED, if it is clearly not ALPROTO_TEMPLATE,
225 * otherwise ALPROTO_UNKNOWN.
227 static AppProto
TemplateProbingParserTc(Flow
*f
, uint8_t direction
,
228 const uint8_t *input
, uint32_t input_len
, uint8_t *rdir
)
230 /* Very simple test - if there is input, this is template. */
231 if (input_len
>= TEMPLATE_MIN_FRAME_LEN
) {
232 SCLogNotice("Detected as ALPROTO_TEMPLATE.");
233 return ALPROTO_TEMPLATE
;
236 SCLogNotice("Protocol not detected as ALPROTO_TEMPLATE.");
237 return ALPROTO_UNKNOWN
;
240 static AppLayerResult
TemplateParseRequest(Flow
*f
, void *statev
,
241 AppLayerParserState
*pstate
, const uint8_t *input
, uint32_t input_len
,
242 void *local_data
, const uint8_t flags
)
244 TemplateState
*state
= statev
;
246 SCLogNotice("Parsing template request: len=%"PRIu32
, input_len
);
249 if (AppLayerParserStateIssetFlag(pstate
, APP_LAYER_PARSER_EOF_TS
)) {
250 /* This is a signal that the stream is done. Do any
251 * cleanup if needed. Usually nothing is required here. */
252 SCReturnStruct(APP_LAYER_OK
);
253 } else if (flags
& STREAM_GAP
) {
254 /* This is a signal that there has been a gap in the
255 * stream. This only needs to be handled if gaps were
256 * enabled during protocol registration. The input_len
257 * contains the size of the gap. */
258 SCReturnStruct(APP_LAYER_OK
);
260 /* This should not happen. If input is NULL, one of the above should be
262 DEBUG_VALIDATE_BUG_ON(true);
263 SCReturnStruct(APP_LAYER_ERROR
);
266 /* Normally you would parse out data here and store it in the
267 * transaction object, but as this is echo, we'll just record the
270 /* Also, if this protocol may have a "protocol data unit" span
271 * multiple chunks of data, which is always a possibility with
272 * TCP, you may need to do some buffering here.
274 * For the sake of simplicity, buffering is left out here, but
275 * even for an echo protocol we may want to buffer until a new
276 * line is seen, assuming its text based.
279 /* Allocate a transaction.
281 * But note that if a "protocol data unit" is not received in one
282 * chunk of data, and the buffering is done on the transaction, we
283 * may need to look for the transaction that this newly received
286 TemplateTransaction
*tx
= TemplateTxAlloc(state
);
287 if (unlikely(tx
== NULL
)) {
288 SCLogNotice("Failed to allocate new Template tx.");
291 SCLogNotice("Allocated Template tx %"PRIu64
".", tx
->tx_id
);
293 /* Make a copy of the request. */
294 tx
->request_buffer
= SCCalloc(1, input_len
);
295 if (unlikely(tx
->request_buffer
== NULL
)) {
298 memcpy(tx
->request_buffer
, input
, input_len
);
299 tx
->request_buffer_len
= input_len
;
301 /* Here we check for an empty message and create an app-layer
303 if ((input_len
== 1 && tx
->request_buffer
[0] == '\n') ||
304 (input_len
== 2 && tx
->request_buffer
[0] == '\r')) {
305 SCLogNotice("Creating event for empty message.");
306 AppLayerDecoderEventsSetEventRaw(&tx
->decoder_events
,
307 TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE
);
311 SCReturnStruct(APP_LAYER_OK
);
314 static AppLayerResult
TemplateParseResponse(Flow
*f
, void *statev
, AppLayerParserState
*pstate
,
315 const uint8_t *input
, uint32_t input_len
, void *local_data
,
318 TemplateState
*state
= statev
;
319 TemplateTransaction
*tx
= NULL
, *ttx
;
321 SCLogNotice("Parsing Template response.");
323 /* Likely connection closed, we can just return here. */
324 if ((input
== NULL
|| input_len
== 0) &&
325 AppLayerParserStateIssetFlag(pstate
, APP_LAYER_PARSER_EOF_TC
)) {
326 SCReturnStruct(APP_LAYER_OK
);
329 /* Probably don't want to create a transaction in this case
331 if (input
== NULL
|| input_len
== 0) {
332 SCReturnStruct(APP_LAYER_OK
);
335 /* Look up the existing transaction for this response. In the case
336 * of echo, it will be the most recent transaction on the
337 * TemplateState object. */
339 /* We should just grab the last transaction, but this is to
340 * illustrate how you might traverse the transaction list to find
341 * the transaction associated with this response. */
342 TAILQ_FOREACH(ttx
, &state
->tx_list
, next
) {
347 SCLogNotice("Failed to find transaction for response on state %p.",
352 SCLogNotice("Found transaction %"PRIu64
" for response on state %p.",
355 /* If the protocol requires multiple chunks of data to complete, you may
356 * run into the case where you have existing response data.
358 * In this case, we just log that there is existing data and free it. But
359 * you might want to realloc the buffer and append the data.
361 if (tx
->response_buffer
!= NULL
) {
362 SCLogNotice("WARNING: Transaction already has response data, "
363 "existing data will be overwritten.");
364 SCFree(tx
->response_buffer
);
367 /* Make a copy of the response. */
368 tx
->response_buffer
= SCCalloc(1, input_len
);
369 if (unlikely(tx
->response_buffer
== NULL
)) {
372 memcpy(tx
->response_buffer
, input
, input_len
);
373 tx
->response_buffer_len
= input_len
;
375 /* Set the response_done flag for transaction state checking in
376 * TemplateGetStateProgress(). */
377 tx
->response_done
= 1;
380 SCReturnStruct(APP_LAYER_OK
);
383 static uint64_t TemplateGetTxCnt(void *statev
)
385 const TemplateState
*state
= statev
;
386 SCLogNotice("Current tx count is %"PRIu64
".", state
->transaction_max
);
387 return state
->transaction_max
;
390 static void *TemplateGetTx(void *statev
, uint64_t tx_id
)
392 TemplateState
*state
= statev
;
393 TemplateTransaction
*tx
;
395 SCLogNotice("Requested tx ID %"PRIu64
".", tx_id
);
397 TAILQ_FOREACH(tx
, &state
->tx_list
, next
) {
398 if (tx
->tx_id
== tx_id
) {
399 SCLogNotice("Transaction %"PRIu64
" found, returning tx object %p.",
405 SCLogNotice("Transaction ID %"PRIu64
" not found.", tx_id
);
410 * \brief Return the state of a transaction in a given direction.
412 * In the case of the echo protocol, the existence of a transaction
413 * means that the request is done. However, some protocols that may
414 * need multiple chunks of data to complete the request may need more
415 * than just the existence of a transaction for the request to be
416 * considered complete.
418 * For the response to be considered done, the response for a request
419 * needs to be seen. The response_done flag is set on response for
422 static int TemplateGetStateProgress(void *txv
, uint8_t direction
)
424 TemplateTransaction
*tx
= txv
;
426 SCLogNotice("Transaction progress requested for tx ID %"PRIu64
427 ", direction=0x%02x", tx
->tx_id
, direction
);
429 if (direction
& STREAM_TOCLIENT
&& tx
->response_done
) {
432 else if (direction
& STREAM_TOSERVER
) {
433 /* For the template, just the existence of the transaction means the
434 * request is done. */
442 * \brief retrieve the tx data used for logging, config, detection
444 static AppLayerTxData
*TemplateGetTxData(void *vtx
)
446 TemplateTransaction
*tx
= vtx
;
450 void RegisterTemplateParsers(void)
452 const char *proto_name
= "template";
454 /* Check if Template TCP detection is enabled. If it does not exist in
455 * the configuration file then it will be disabled by default. */
456 if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("tcp", proto_name
, false)) {
458 SCLogDebug("Template TCP protocol detection enabled.");
460 AppLayerProtoDetectRegisterProtocol(ALPROTO_TEMPLATE
, proto_name
);
462 if (RunmodeIsUnittests()) {
464 SCLogNotice("Unittest mode, registering default configuration.");
465 AppLayerProtoDetectPPRegister(IPPROTO_TCP
, TEMPLATE_DEFAULT_PORT
,
466 ALPROTO_TEMPLATE
, 0, TEMPLATE_MIN_FRAME_LEN
, STREAM_TOSERVER
,
467 TemplateProbingParserTs
, TemplateProbingParserTc
);
472 if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP
,
473 proto_name
, ALPROTO_TEMPLATE
, 0, TEMPLATE_MIN_FRAME_LEN
,
474 TemplateProbingParserTs
, TemplateProbingParserTc
)) {
475 SCLogDebug("No template app-layer configuration, enabling echo"
476 " detection TCP detection on port %s.",
477 TEMPLATE_DEFAULT_PORT
);
478 AppLayerProtoDetectPPRegister(IPPROTO_TCP
,
479 TEMPLATE_DEFAULT_PORT
, ALPROTO_TEMPLATE
, 0,
480 TEMPLATE_MIN_FRAME_LEN
, STREAM_TOSERVER
,
481 TemplateProbingParserTs
, TemplateProbingParserTc
);
489 SCLogDebug("Protocol detector and parser disabled for Template.");
493 if (AppLayerParserConfParserEnabled("tcp", proto_name
)) {
495 SCLogNotice("Registering Template protocol parser.");
497 /* Register functions for state allocation and freeing. A
498 * state is allocated for every new Template flow. */
499 AppLayerParserRegisterStateFuncs(IPPROTO_TCP
, ALPROTO_TEMPLATE
,
500 TemplateStateAlloc
, TemplateStateFree
);
502 /* Register request parser for parsing frame from server to client. */
503 AppLayerParserRegisterParser(IPPROTO_TCP
, ALPROTO_TEMPLATE
,
504 STREAM_TOSERVER
, TemplateParseRequest
);
506 /* Register response parser for parsing frames from server to client. */
507 AppLayerParserRegisterParser(IPPROTO_TCP
, ALPROTO_TEMPLATE
,
508 STREAM_TOCLIENT
, TemplateParseResponse
);
510 /* Register a function to be called by the application layer
511 * when a transaction is to be freed. */
512 AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP
, ALPROTO_TEMPLATE
,
513 TemplateStateTxFree
);
515 /* Register a function to return the current transaction count. */
516 AppLayerParserRegisterGetTxCnt(IPPROTO_TCP
, ALPROTO_TEMPLATE
,
519 /* Transaction handling. */
520 AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_TEMPLATE
, 1, 1);
521 AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP
,
522 ALPROTO_TEMPLATE
, TemplateGetStateProgress
);
523 AppLayerParserRegisterGetTx(IPPROTO_TCP
, ALPROTO_TEMPLATE
,
525 AppLayerParserRegisterTxDataFunc(IPPROTO_TCP
, ALPROTO_TEMPLATE
,
528 AppLayerParserRegisterGetEventInfo(IPPROTO_TCP
, ALPROTO_TEMPLATE
,
529 TemplateStateGetEventInfo
);
530 AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP
, ALPROTO_TEMPLATE
,
531 TemplateStateGetEventInfoById
);
532 AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP
, ALPROTO_TEMPLATE
,
535 /* Leave this is if your parser can handle gaps, otherwise
537 AppLayerParserRegisterOptionFlags(IPPROTO_TCP
, ALPROTO_TEMPLATE
,
538 APP_LAYER_PARSER_OPT_ACCEPT_GAPS
);
541 SCLogDebug("Template protocol parsing disabled.");
545 AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP
, ALPROTO_TEMPLATE
,
546 TemplateParserRegisterTests
);
553 void TemplateParserRegisterTests(void)