suricata
app-layer-template.c
Go to the documentation of this file.
1 /* Copyright (C) 2015 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 
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 {
66 };
67 
69  {"EMPTY_MESSAGE", TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE},
70 
71  // event table must be NULL-terminated
72  { NULL, -1 },
73 };
74 
75 static TemplateTransaction *TemplateTxAlloc(TemplateState *state)
76 {
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 
91 static void TemplateTxFree(void *txv)
92 {
93  TemplateTransaction *tx = txv;
94 
95  if (tx->request_buffer != NULL) {
97  }
98 
99  if (tx->response_buffer != NULL) {
100  SCFree(tx->response_buffer);
101  }
102 
104 
105  SCFree(tx);
106 }
107 
108 static void *TemplateStateAlloc(void)
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 
119 static void TemplateStateFree(void *state)
120 {
121  TemplateState *template_state = state;
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  */
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 
161 static int TemplateStateGetEventInfo(const char *event_name, int *event_id,
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 
177 static int TemplateStateGetEventInfoById(int event_id, const char **event_name,
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 
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  */
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  */
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 
240 static int 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  /* Likely connection closed, we can just return here. */
249  if ((input == NULL || input_len == 0) &&
251  return 0;
252  }
253 
254  /* Probably don't want to create a transaction in this case
255  * either. */
256  if (input == NULL || input_len == 0) {
257  return 0;
258  }
259 
260  /* Normally you would parse out data here and store it in the
261  * transaction object, but as this is echo, we'll just record the
262  * request data. */
263 
264  /* Also, if this protocol may have a "protocol data unit" span
265  * multiple chunks of data, which is always a possibility with
266  * TCP, you may need to do some buffering here.
267  *
268  * For the sake of simplicity, buffering is left out here, but
269  * even for an echo protocol we may want to buffer until a new
270  * line is seen, assuming its text based.
271  */
272 
273  /* Allocate a transaction.
274  *
275  * But note that if a "protocol data unit" is not received in one
276  * chunk of data, and the buffering is done on the transaction, we
277  * may need to look for the transaction that this newly recieved
278  * data belongs to.
279  */
280  TemplateTransaction *tx = TemplateTxAlloc(state);
281  if (unlikely(tx == NULL)) {
282  SCLogNotice("Failed to allocate new Template tx.");
283  goto end;
284  }
285  SCLogNotice("Allocated Template tx %"PRIu64".", tx->tx_id);
286 
287  /* Make a copy of the request. */
288  tx->request_buffer = SCCalloc(1, input_len);
289  if (unlikely(tx->request_buffer == NULL)) {
290  goto end;
291  }
292  memcpy(tx->request_buffer, input, input_len);
293  tx->request_buffer_len = input_len;
294 
295  /* Here we check for an empty message and create an app-layer
296  * event. */
297  if ((input_len == 1 && tx->request_buffer[0] == '\n') ||
298  (input_len == 2 && tx->request_buffer[0] == '\r')) {
299  SCLogNotice("Creating event for empty message.");
302  }
303 
304 end:
305  return 0;
306 }
307 
308 static int TemplateParseResponse(Flow *f, void *statev, AppLayerParserState *pstate,
309  const uint8_t *input, uint32_t input_len, void *local_data,
310  const uint8_t flags)
311 {
312  TemplateState *state = statev;
313  TemplateTransaction *tx = NULL, *ttx;
314 
315  SCLogNotice("Parsing Template response.");
316 
317  /* Likely connection closed, we can just return here. */
318  if ((input == NULL || input_len == 0) &&
320  return 0;
321  }
322 
323  /* Probably don't want to create a transaction in this case
324  * either. */
325  if (input == NULL || input_len == 0) {
326  return 0;
327  }
328 
329  /* Look up the existing transaction for this response. In the case
330  * of echo, it will be the most recent transaction on the
331  * TemplateState object. */
332 
333  /* We should just grab the last transaction, but this is to
334  * illustrate how you might traverse the transaction list to find
335  * the transaction associated with this response. */
336  TAILQ_FOREACH(ttx, &state->tx_list, next) {
337  tx = ttx;
338  }
339 
340  if (tx == NULL) {
341  SCLogNotice("Failed to find transaction for response on state %p.",
342  state);
343  goto end;
344  }
345 
346  SCLogNotice("Found transaction %"PRIu64" for response on state %p.",
347  tx->tx_id, state);
348 
349  /* If the protocol requires multiple chunks of data to complete, you may
350  * run into the case where you have existing response data.
351  *
352  * In this case, we just log that there is existing data and free it. But
353  * you might want to realloc the buffer and append the data.
354  */
355  if (tx->response_buffer != NULL) {
356  SCLogNotice("WARNING: Transaction already has response data, "
357  "existing data will be overwritten.");
358  SCFree(tx->response_buffer);
359  }
360 
361  /* Make a copy of the response. */
362  tx->response_buffer = SCCalloc(1, input_len);
363  if (unlikely(tx->response_buffer == NULL)) {
364  goto end;
365  }
366  memcpy(tx->response_buffer, input, input_len);
367  tx->response_buffer_len = input_len;
368 
369  /* Set the response_done flag for transaction state checking in
370  * TemplateGetStateProgress(). */
371  tx->response_done = 1;
372 
373 end:
374  return 0;
375 }
376 
377 static uint64_t TemplateGetTxCnt(void *statev)
378 {
379  const TemplateState *state = statev;
380  SCLogNotice("Current tx count is %"PRIu64".", state->transaction_max);
381  return state->transaction_max;
382 }
383 
384 static void *TemplateGetTx(void *statev, uint64_t tx_id)
385 {
386  TemplateState *state = statev;
388 
389  SCLogNotice("Requested tx ID %"PRIu64".", tx_id);
390 
391  TAILQ_FOREACH(tx, &state->tx_list, next) {
392  if (tx->tx_id == tx_id) {
393  SCLogNotice("Transaction %"PRIu64" found, returning tx object %p.",
394  tx_id, tx);
395  return tx;
396  }
397  }
398 
399  SCLogNotice("Transaction ID %"PRIu64" not found.", tx_id);
400  return NULL;
401 }
402 
403 static void TemplateSetTxLogged(void *state, void *vtx, LoggerId logged)
404 {
406  tx->logged = logged;
407 }
408 
409 static LoggerId TemplateGetTxLogged(void *state, void *vtx)
410 {
411  const TemplateTransaction *tx = (TemplateTransaction *)vtx;
412  return tx->logged;
413 }
414 
415 /**
416  * \brief Called by the application layer.
417  *
418  * In most cases 1 can be returned here.
419  */
420 static int TemplateGetAlstateProgressCompletionStatus(uint8_t direction) {
421  return 1;
422 }
423 
424 /**
425  * \brief Return the state of a transaction in a given direction.
426  *
427  * In the case of the echo protocol, the existence of a transaction
428  * means that the request is done. However, some protocols that may
429  * need multiple chunks of data to complete the request may need more
430  * than just the existence of a transaction for the request to be
431  * considered complete.
432  *
433  * For the response to be considered done, the response for a request
434  * needs to be seen. The response_done flag is set on response for
435  * checking here.
436  */
437 static int TemplateGetStateProgress(void *txv, uint8_t direction)
438 {
439  TemplateTransaction *tx = txv;
440 
441  SCLogNotice("Transaction progress requested for tx ID %"PRIu64
442  ", direction=0x%02x", tx->tx_id, direction);
443 
444  if (direction & STREAM_TOCLIENT && tx->response_done) {
445  return 1;
446  }
447  else if (direction & STREAM_TOSERVER) {
448  /* For the template, just the existence of the transaction means the
449  * request is done. */
450  return 1;
451  }
452 
453  return 0;
454 }
455 
456 /**
457  * \brief retrieve the detection engine per tx state
458  */
459 static DetectEngineState *TemplateGetTxDetectState(void *vtx)
460 {
461  TemplateTransaction *tx = vtx;
462  return tx->de_state;
463 }
464 
465 /**
466  * \brief get the detection engine per tx state
467  */
468 static int TemplateSetTxDetectState(void *vtx,
470 {
471  TemplateTransaction *tx = vtx;
472  tx->de_state = s;
473  return 0;
474 }
475 
477 {
478  const char *proto_name = "template";
479 
480  /* TEMPLATE_START_REMOVE */
481  if (ConfGetNode("app-layer.protocols.template") == NULL) {
482  return;
483  }
484  /* TEMPLATE_END_REMOVE */
485  /* Check if Template TCP detection is enabled. If it does not exist in
486  * the configuration file then it will be enabled by default. */
487  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
488 
489  SCLogNotice("Template TCP protocol detection enabled.");
490 
492 
493  if (RunmodeIsUnittests()) {
494 
495  SCLogNotice("Unittest mode, registeringd default configuration.");
498  TemplateProbingParserTs, TemplateProbingParserTc);
499 
500  }
501  else {
502 
503  if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP,
505  TemplateProbingParserTs, TemplateProbingParserTc)) {
506  SCLogNotice("No template app-layer configuration, enabling echo"
507  " detection TCP detection on port %s.",
509  AppLayerProtoDetectPPRegister(IPPROTO_TCP,
512  TemplateProbingParserTs, TemplateProbingParserTc);
513  }
514 
515  }
516 
517  }
518 
519  else {
520  SCLogNotice("Protocol detecter and parser disabled for Template.");
521  return;
522  }
523 
524  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
525 
526  SCLogNotice("Registering Template protocol parser.");
527 
528  /* Register functions for state allocation and freeing. A
529  * state is allocated for every new Template flow. */
531  TemplateStateAlloc, TemplateStateFree);
532 
533  /* Register request parser for parsing frame from server to client. */
535  STREAM_TOSERVER, TemplateParseRequest);
536 
537  /* Register response parser for parsing frames from server to client. */
539  STREAM_TOCLIENT, TemplateParseResponse);
540 
541  /* Register a function to be called by the application layer
542  * when a transaction is to be freed. */
544  TemplateStateTxFree);
545 
547  TemplateGetTxLogged, TemplateSetTxLogged);
548 
549  /* Register a function to return the current transaction count. */
551  TemplateGetTxCnt);
552 
553  /* Transaction handling. */
555  TemplateGetAlstateProgressCompletionStatus);
557  ALPROTO_TEMPLATE, TemplateGetStateProgress);
559  TemplateGetTx);
560 
561  /* What is this being registered for? */
563  TemplateGetTxDetectState, TemplateSetTxDetectState);
564 
566  TemplateStateGetEventInfo);
568  TemplateStateGetEventInfoById);
570  TemplateGetEvents);
571  }
572  else {
573  SCLogNotice("Template protocol parsing disabled.");
574  }
575 
576 #ifdef UNITTESTS
579 #endif
580 }
581 
582 #ifdef UNITTESTS
583 #endif
584 
586 {
587 #ifdef UNITTESTS
588 #endif
589 }
enum AppLayerEventType_ AppLayerEventType
uint16_t flags
const char * SCMapEnumValueToName(int enum_value, SCEnumCharMap *table)
Maps an enum value to a string name, from the supplied table.
Definition: util-enum.c:69
#define TAILQ_FIRST(head)
Definition: queue.h:339
void AppLayerProtoDetectPPRegister(uint8_t ipproto, const char *portstr, AppProto alproto, uint16_t min_depth, uint16_t max_depth, uint8_t direction, ProbingParserFPtr ProbingParser1, ProbingParserFPtr ProbingParser2)
register parser at a port
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:350
struct HtpBodyChunk_ * next
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
uint32_t event_type
LoggerId
int logged
#define unlikely(expr)
Definition: util-optimize.h:35
int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
Given a protocol name, checks if proto detection is enabled in the conf file.
int AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint8_t flag)
void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, DetectEngineState *(*GetTxDetectState)(void *tx), int(*SetTxDetectState)(void *tx, DetectEngineState *))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:356
void AppLayerDecoderEventsSetEventRaw(AppLayerDecoderEvents **sevents, uint8_t event)
Set an app layer decoder event.
void AppLayerParserRegisterGetEventsFunc(uint8_t ipproto, AppProto alproto, AppLayerDecoderEvents *(*StateGetEvents)(void *))
int SCMapEnumNameToValue(const char *enum_name, SCEnumCharMap *table)
Maps a string name to an enum value from the supplied table. Please specify the last element of any m...
Definition: util-enum.c:41
void AppLayerParserRegisterLoggerFuncs(uint8_t ipproto, AppProto alproto, LoggerId(*StateGetTxLogged)(void *, void *), void(*StateSetTxLogged)(void *, void *, LoggerId))
uint16_t AppProto
void RegisterTemplateParsers(void)
SCEnumCharMap template_decoder_event_table[]
int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name)
check if a parser is enabled in the config Returns enabled always if: were running unittests and when...
#define SCCalloc(nm, a)
Definition: util-mem.h:253
Data structure to store app layer decoder events.
int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, uint8_t direction, AppLayerParserFPtr Parser)
Register app layer parser for the protocol.
#define TEMPLATE_MIN_FRAME_LEN
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
#define TAILQ_INIT(head)
Definition: queue.h:370
int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, uint8_t ipproto, const char *alproto_name, AppProto alproto, uint16_t min_depth, uint16_t max_depth, ProbingParserFPtr ProbingParserTs, ProbingParserFPtr ProbingParserTc)
void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, int(*StateGetEventInfo)(const char *event_name, int *event_id, AppLayerEventType *event_type))
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:412
#define STREAM_TOCLIENT
Definition: stream.h:32
void AppLayerParserRegisterGetStateProgressCompletionStatus(AppProto alproto, int(*StateGetProgressCompletionStatus)(uint8_t direction))
int RunmodeIsUnittests(void)
Definition: suricata.c:267
void AppLayerParserRegisterGetEventInfoById(uint8_t ipproto, AppProto alproto, int(*StateGetEventInfoById)(int event_id, const char **event_name, AppLayerEventType *event_type))
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:385
void AppLayerDecoderEventsFreeEvents(AppLayerDecoderEvents **events)
void TemplateParserRegisterTests(void)
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
#define SCFree(a)
Definition: util-mem.h:322
#define TEMPLATE_DEFAULT_PORT
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:269
uint16_t tx_id
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
#define STREAM_TOSERVER
Definition: stream.h:31
uint64_t transaction_max
#define APP_LAYER_PARSER_EOF
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:176
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void), void(*StateFree)(void *))
DetectEngineState * de_state
Flow data structure.
Definition: flow.h:325
AppLayerDecoderEvents * decoder_events
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))