1 /* Copyright (C) 2015-2020 Open Information Security Foundation
2 *
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
5 * Software Foundation.
6 *
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.
11 *
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
15 * 02110-1301, USA.
16 */
17
18 /*
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.
22 */
23
24 /**
25 * \file
26 *
27 * \author FirstName LastName <yourname@domain>
28 *
29 * Template application layer detector and parser for learning and
30 * template pruposes.
31 *
32 * This template implements a simple application layer for something
33 * like the echo protocol running on port 7.
34 */
35
36 #include "suricata-common.h"
37 #include "stream.h"
38 #include "conf.h"
39 #include "app-layer-detect-proto.h"
40 #include "app-layer-parser.h"
41 #include "app-layer-template.h"
42
43 #include "util-unittest.h"
44 #include "util-validate.h"
45
46 /* The default port to probe for echo traffic if not provided in the
47 * configuration file. */
48 #define TEMPLATE_DEFAULT_PORT "7"
49
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
53
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.
58 *
59 * Example rule:
60 *
61 * alert template any any -> any any (msg:"SURICATA Template empty message"; \
62 * app-layer-event:template.empty_message; sid:X; rev:Y;)
63 */
64 enum {
65 TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE,
66 };
67
68 SCEnumCharMap template_decoder_event_table[] = {
69 {"EMPTY_MESSAGE", TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE},
70
71 // event table must be NULL-terminated
72 { NULL, -1 },
73 };
74
TemplateTxAlloc(TemplateState * state)75 static TemplateTransaction *TemplateTxAlloc(TemplateState *state)
76 {
77 TemplateTransaction *tx = SCCalloc(1, sizeof(TemplateTransaction));
78 if (unlikely(tx == NULL)) {
79 return NULL;
80 }
81
82 /* Increment the transaction ID on the state each time one is
83 * allocated. */
84 tx->tx_id = state->transaction_max++;
85
86 TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
87
88 return tx;
89 }
90
TemplateTxFree(void * txv)91 static void TemplateTxFree(void *txv)
92 {
93 TemplateTransaction *tx = txv;
94
95 if (tx->request_buffer != NULL) {
96 SCFree(tx->request_buffer);
97 }
98
99 if (tx->response_buffer != NULL) {
100 SCFree(tx->response_buffer);
101 }
102
103 AppLayerDecoderEventsFreeEvents(&tx->decoder_events);
104
105 SCFree(tx);
106 }
107
TemplateStateAlloc(void * orig_state,AppProto proto_orig)108 static void *TemplateStateAlloc(void *orig_state, AppProto proto_orig)
109 {
110 SCLogNotice("Allocating template state.");
111 TemplateState *state = SCCalloc(1, sizeof(TemplateState));
112 if (unlikely(state == NULL)) {
113 return NULL;
114 }
115 TAILQ_INIT(&state->tx_list);
116 return state;
117 }
118
TemplateStateFree(void * state)119 static void TemplateStateFree(void *state)
120 {
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);
126 TemplateTxFree(tx);
127 }
128 SCFree(template_state);
129 }
130
131 /**
132 * \brief Callback from the application layer to have a transaction freed.
133 *
134 * \param state a void pointer to the TemplateState object.
135 * \param tx_id the transaction ID to free.
136 */
TemplateStateTxFree(void * statev,uint64_t tx_id)137 static void TemplateStateTxFree(void *statev, uint64_t tx_id)
138 {
139 TemplateState *state = statev;
140 TemplateTransaction *tx = NULL, *ttx;
141
142 SCLogNotice("Freeing transaction %"PRIu64, tx_id);
143
144 TAILQ_FOREACH_SAFE(tx, &state->tx_list, next, ttx) {
145
146 /* Continue if this is not the transaction we are looking
147 * for. */
148 if (tx->tx_id != tx_id) {
149 continue;
150 }
151
152 /* Remove and free the transaction. */
153 TAILQ_REMOVE(&state->tx_list, tx, next);
154 TemplateTxFree(tx);
155 return;
156 }
157
158 SCLogNotice("Transaction %"PRIu64" not found.", tx_id);
159 }
160
TemplateStateGetEventInfo(const char * event_name,int * event_id,AppLayerEventType * event_type)161 static int TemplateStateGetEventInfo(const char *event_name, int *event_id,
162 AppLayerEventType *event_type)
163 {
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. */
169 return -1;
170 }
171
172 *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
173
174 return 0;
175 }
176
TemplateStateGetEventInfoById(int event_id,const char ** event_name,AppLayerEventType * event_type)177 static int TemplateStateGetEventInfoById(int event_id, const char **event_name,
178 AppLayerEventType *event_type)
179 {
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. */
185 return -1;
186 }
187
188 *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
189
190 return 0;
191 }
192
TemplateGetEvents(void * tx)193 static AppLayerDecoderEvents *TemplateGetEvents(void *tx)
194 {
195 return ((TemplateTransaction *)tx)->decoder_events;
196 }
197
198 /**
199 * \brief Probe the input to server to see if it looks like template.
200 *
201 * \retval ALPROTO_TEMPLATE if it looks like template,
202 * ALPROTO_FAILED, if it is clearly not ALPROTO_TEMPLATE,
203 * otherwise ALPROTO_UNKNOWN.
204 */
TemplateProbingParserTs(Flow * f,uint8_t direction,const uint8_t * input,uint32_t input_len,uint8_t * rdir)205 static AppProto TemplateProbingParserTs(Flow *f, uint8_t direction,
206 const uint8_t *input, uint32_t input_len, uint8_t *rdir)
207 {
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;
212 }
213
214 SCLogNotice("Protocol not detected as ALPROTO_TEMPLATE.");
215 return ALPROTO_UNKNOWN;
216 }
217
218 /**
219 * \brief Probe the input to client to see if it looks like template.
220 * TemplateProbingParserTs can be used instead if the protocol
221 * is symmetric.
222 *
223 * \retval ALPROTO_TEMPLATE if it looks like template,
224 * ALPROTO_FAILED, if it is clearly not ALPROTO_TEMPLATE,
225 * otherwise ALPROTO_UNKNOWN.
226 */
TemplateProbingParserTc(Flow * f,uint8_t direction,const uint8_t * input,uint32_t input_len,uint8_t * rdir)227 static AppProto TemplateProbingParserTc(Flow *f, uint8_t direction,
228 const uint8_t *input, uint32_t input_len, uint8_t *rdir)
229 {
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;
234 }
235
236 SCLogNotice("Protocol not detected as ALPROTO_TEMPLATE.");
237 return ALPROTO_UNKNOWN;
238 }
239
TemplateParseRequest(Flow * f,void * statev,AppLayerParserState * pstate,const uint8_t * input,uint32_t input_len,void * local_data,const uint8_t flags)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)
243 {
244 TemplateState *state = statev;
245
246 SCLogNotice("Parsing template request: len=%"PRIu32, input_len);
247
248 if (input == NULL) {
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);
259 }
260 /* This should not happen. If input is NULL, one of the above should be
261 * true. */
262 DEBUG_VALIDATE_BUG_ON(true);
263 SCReturnStruct(APP_LAYER_ERROR);
264 }
265
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
268 * request data. */
269
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.
273 *
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.
277 */
278
279 /* Allocate a transaction.
280 *
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 recieved
284 * data belongs to.
285 */
286 TemplateTransaction *tx = TemplateTxAlloc(state);
287 if (unlikely(tx == NULL)) {
288 SCLogNotice("Failed to allocate new Template tx.");
289 goto end;
290 }
291 SCLogNotice("Allocated Template tx %"PRIu64".", tx->tx_id);
292
293 /* Make a copy of the request. */
294 tx->request_buffer = SCCalloc(1, input_len);
295 if (unlikely(tx->request_buffer == NULL)) {
296 goto end;
297 }
298 memcpy(tx->request_buffer, input, input_len);
299 tx->request_buffer_len = input_len;
300
301 /* Here we check for an empty message and create an app-layer
302 * event. */
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);
308 }
309
310 end:
311 SCReturnStruct(APP_LAYER_OK);
312 }
313
TemplateParseResponse(Flow * f,void * statev,AppLayerParserState * pstate,const uint8_t * input,uint32_t input_len,void * local_data,const uint8_t flags)314 static AppLayerResult TemplateParseResponse(Flow *f, void *statev, AppLayerParserState *pstate,
315 const uint8_t *input, uint32_t input_len, void *local_data,
316 const uint8_t flags)
317 {
318 TemplateState *state = statev;
319 TemplateTransaction *tx = NULL, *ttx;
320
321 SCLogNotice("Parsing Template response.");
322
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);
327 }
328
329 /* Probably don't want to create a transaction in this case
330 * either. */
331 if (input == NULL || input_len == 0) {
332 SCReturnStruct(APP_LAYER_OK);
333 }
334
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. */
338
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) {
343 tx = ttx;
344 }
345
346 if (tx == NULL) {
347 SCLogNotice("Failed to find transaction for response on state %p.",
348 state);
349 goto end;
350 }
351
352 SCLogNotice("Found transaction %"PRIu64" for response on state %p.",
353 tx->tx_id, state);
354
355 /* If the protocol requires multiple chunks of data to complete, you may
356 * run into the case where you have existing response data.
357 *
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.
360 */
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);
365 }
366
367 /* Make a copy of the response. */
368 tx->response_buffer = SCCalloc(1, input_len);
369 if (unlikely(tx->response_buffer == NULL)) {
370 goto end;
371 }
372 memcpy(tx->response_buffer, input, input_len);
373 tx->response_buffer_len = input_len;
374
375 /* Set the response_done flag for transaction state checking in
376 * TemplateGetStateProgress(). */
377 tx->response_done = 1;
378
379 end:
380 SCReturnStruct(APP_LAYER_OK);
381 }
382
TemplateGetTxCnt(void * statev)383 static uint64_t TemplateGetTxCnt(void *statev)
384 {
385 const TemplateState *state = statev;
386 SCLogNotice("Current tx count is %"PRIu64".", state->transaction_max);
387 return state->transaction_max;
388 }
389
TemplateGetTx(void * statev,uint64_t tx_id)390 static void *TemplateGetTx(void *statev, uint64_t tx_id)
391 {
392 TemplateState *state = statev;
393 TemplateTransaction *tx;
394
395 SCLogNotice("Requested tx ID %"PRIu64".", tx_id);
396
397 TAILQ_FOREACH(tx, &state->tx_list, next) {
398 if (tx->tx_id == tx_id) {
399 SCLogNotice("Transaction %"PRIu64" found, returning tx object %p.",
400 tx_id, tx);
401 return tx;
402 }
403 }
404
405 SCLogNotice("Transaction ID %"PRIu64" not found.", tx_id);
406 return NULL;
407 }
408
409 /**
410 * \brief Called by the application layer.
411 *
412 * In most cases 1 can be returned here.
413 */
TemplateGetAlstateProgressCompletionStatus(uint8_t direction)414 static int TemplateGetAlstateProgressCompletionStatus(uint8_t direction) {
415 return 1;
416 }
417
418 /**
419 * \brief Return the state of a transaction in a given direction.
420 *
421 * In the case of the echo protocol, the existence of a transaction
422 * means that the request is done. However, some protocols that may
423 * need multiple chunks of data to complete the request may need more
424 * than just the existence of a transaction for the request to be
425 * considered complete.
426 *
427 * For the response to be considered done, the response for a request
428 * needs to be seen. The response_done flag is set on response for
429 * checking here.
430 */
TemplateGetStateProgress(void * txv,uint8_t direction)431 static int TemplateGetStateProgress(void *txv, uint8_t direction)
432 {
433 TemplateTransaction *tx = txv;
434
435 SCLogNotice("Transaction progress requested for tx ID %"PRIu64
436 ", direction=0x%02x", tx->tx_id, direction);
437
438 if (direction & STREAM_TOCLIENT && tx->response_done) {
439 return 1;
440 }
441 else if (direction & STREAM_TOSERVER) {
442 /* For the template, just the existence of the transaction means the
443 * request is done. */
444 return 1;
445 }
446
447 return 0;
448 }
449
450 /**
451 * \brief retrieve the tx data used for logging, config, detection
452 */
TemplateGetTxData(void * vtx)453 static AppLayerTxData *TemplateGetTxData(void *vtx)
454 {
455 TemplateTransaction *tx = vtx;
456 return &tx->tx_data;
457 }
458
459 /**
460 * \brief retrieve the detection engine per tx state
461 */
TemplateGetTxDetectState(void * vtx)462 static DetectEngineState *TemplateGetTxDetectState(void *vtx)
463 {
464 TemplateTransaction *tx = vtx;
465 return tx->de_state;
466 }
467
468 /**
469 * \brief get the detection engine per tx state
470 */
TemplateSetTxDetectState(void * vtx,DetectEngineState * s)471 static int TemplateSetTxDetectState(void *vtx,
472 DetectEngineState *s)
473 {
474 TemplateTransaction *tx = vtx;
475 tx->de_state = s;
476 return 0;
477 }
478
RegisterTemplateParsers(void)479 void RegisterTemplateParsers(void)
480 {
481 const char *proto_name = "template";
482
483 /* TEMPLATE_START_REMOVE */
484 if (ConfGetNode("app-layer.protocols.template") == NULL) {
485 return;
486 }
487 /* TEMPLATE_END_REMOVE */
488 /* Check if Template TCP detection is enabled. If it does not exist in
489 * the configuration file then it will be enabled by default. */
490 if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
491
492 SCLogNotice("Template TCP protocol detection enabled.");
493
494 AppLayerProtoDetectRegisterProtocol(ALPROTO_TEMPLATE, proto_name);
495
496 if (RunmodeIsUnittests()) {
497
498 SCLogNotice("Unittest mode, registeringd default configuration.");
499 AppLayerProtoDetectPPRegister(IPPROTO_TCP, TEMPLATE_DEFAULT_PORT,
500 ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN, STREAM_TOSERVER,
501 TemplateProbingParserTs, TemplateProbingParserTc);
502
503 }
504 else {
505
506 if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP,
507 proto_name, ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN,
508 TemplateProbingParserTs, TemplateProbingParserTc)) {
509 SCLogNotice("No template app-layer configuration, enabling echo"
510 " detection TCP detection on port %s.",
511 TEMPLATE_DEFAULT_PORT);
512 AppLayerProtoDetectPPRegister(IPPROTO_TCP,
513 TEMPLATE_DEFAULT_PORT, ALPROTO_TEMPLATE, 0,
514 TEMPLATE_MIN_FRAME_LEN, STREAM_TOSERVER,
515 TemplateProbingParserTs, TemplateProbingParserTc);
516 }
517
518 }
519
520 }
521
522 else {
523 SCLogNotice("Protocol detecter and parser disabled for Template.");
524 return;
525 }
526
527 if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
528
529 SCLogNotice("Registering Template protocol parser.");
530
531 /* Register functions for state allocation and freeing. A
532 * state is allocated for every new Template flow. */
533 AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_TEMPLATE,
534 TemplateStateAlloc, TemplateStateFree);
535
536 /* Register request parser for parsing frame from server to client. */
537 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEMPLATE,
538 STREAM_TOSERVER, TemplateParseRequest);
539
540 /* Register response parser for parsing frames from server to client. */
541 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEMPLATE,
542 STREAM_TOCLIENT, TemplateParseResponse);
543
544 /* Register a function to be called by the application layer
545 * when a transaction is to be freed. */
546 AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_TEMPLATE,
547 TemplateStateTxFree);
548
549 /* Register a function to return the current transaction count. */
550 AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TEMPLATE,
551 TemplateGetTxCnt);
552
553 /* Transaction handling. */
554 AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_TEMPLATE,
555 TemplateGetAlstateProgressCompletionStatus);
556 AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP,
557 ALPROTO_TEMPLATE, TemplateGetStateProgress);
558 AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_TEMPLATE,
559 TemplateGetTx);
560 AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_TEMPLATE,
561 TemplateGetTxData);
562
563 /* What is this being registered for? */
564 AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_TEMPLATE,
565 TemplateGetTxDetectState, TemplateSetTxDetectState);
566
567 AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_TEMPLATE,
568 TemplateStateGetEventInfo);
569 AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_TEMPLATE,
570 TemplateStateGetEventInfoById);
571 AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_TEMPLATE,
572 TemplateGetEvents);
573
574 /* Leave this is if you parser can handle gaps, otherwise
575 * remove. */
576 AppLayerParserRegisterOptionFlags(IPPROTO_TCP, ALPROTO_TEMPLATE,
577 APP_LAYER_PARSER_OPT_ACCEPT_GAPS);
578 }
579 else {
580 SCLogNotice("Template protocol parsing disabled.");
581 }
582
583 #ifdef UNITTESTS
584 AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_TEMPLATE,
585 TemplateParserRegisterTests);
586 #endif
587 }
588
589 #ifdef UNITTESTS
590 #endif
591
TemplateParserRegisterTests(void)592 void TemplateParserRegisterTests(void)
593 {
594 #ifdef UNITTESTS
595 #endif
596 }
597