]> git.ipfire.org Git - people/ms/suricata.git/blame - src/app-layer-template.c
decode-icmpv6: use FAIL macros in tests
[people/ms/suricata.git] / src / app-layer-template.c
CommitLineData
c1b92126
JI
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 * \file Template application layer detector and parser for learning and
20 * template pruposes.
21 *
22 * This template implements a simple application layer for something
23 * like the echo protocol running on port 7.
24 */
25
26#include "suricata-common.h"
27#include "stream.h"
9697a09d 28#include "conf.h"
c1b92126
JI
29
30#include "util-unittest.h"
31
32#include "app-layer-detect-proto.h"
33#include "app-layer-parser.h"
34
35#include "app-layer-template.h"
36
37/* The default port to probe for echo traffic if not provided in the
38 * configuration file. */
39#define TEMPLATE_DEFAULT_PORT "7"
40
41/* The minimum size for an echo message. For some protocols this might
42 * be the size of a header. */
43#define TEMPLATE_MIN_FRAME_LEN 1
44
45/* Enum of app-layer events for an echo protocol. Normally you might
46 * have events for errors in parsing data, like unexpected data being
47 * received. For echo we'll make something up, and log an app-layer
48 * level alert if an empty message is received.
49 *
50 * Example rule:
51 *
3da79610 52 * alert template any any -> any any (msg:"SURICATA Template empty message"; \
c1b92126
JI
53 * app-layer-event:template.empty_message; sid:X; rev:Y;)
54 */
55enum {
56 TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE,
57};
58
59SCEnumCharMap template_decoder_event_table[] = {
60 {"EMPTY_MESSAGE", TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE},
61};
62
63static TemplateTransaction *TemplateTxAlloc(TemplateState *echo)
64{
65 TemplateTransaction *tx = SCCalloc(1, sizeof(TemplateTransaction));
66 if (unlikely(tx == NULL)) {
67 return NULL;
68 }
69
70 /* Increment the transaction ID on the state each time one is
71 * allocated. */
72 tx->tx_id = echo->transaction_max++;
73
74 TAILQ_INSERT_TAIL(&echo->tx_list, tx, next);
75
76 return tx;
77}
78
79static void TemplateTxFree(void *tx)
80{
81 TemplateTransaction *templatetx = tx;
82
83 if (templatetx->request_buffer != NULL) {
84 SCFree(templatetx->request_buffer);
85 }
86
87 if (templatetx->response_buffer != NULL) {
88 SCFree(templatetx->response_buffer);
89 }
90
91 AppLayerDecoderEventsFreeEvents(&templatetx->decoder_events);
92
93 SCFree(tx);
94}
95
96static void *TemplateStateAlloc(void)
97{
98 SCLogNotice("Allocating template state.");
99 TemplateState *state = SCCalloc(1, sizeof(TemplateState));
100 if (unlikely(state == NULL)) {
101 return NULL;
102 }
103 TAILQ_INIT(&state->tx_list);
104 return state;
105}
106
107static void TemplateStateFree(void *state)
108{
109 TemplateState *template_state = state;
110 TemplateTransaction *tx;
111 SCLogNotice("Freeing template state.");
112 while ((tx = TAILQ_FIRST(&template_state->tx_list)) != NULL) {
113 TAILQ_REMOVE(&template_state->tx_list, tx, next);
114 TemplateTxFree(tx);
115 }
116 SCFree(template_state);
117}
118
119/**
120 * \brief Callback from the application layer to have a transaction freed.
121 *
122 * \param state a void pointer to the TemplateState object.
123 * \param tx_id the transaction ID to free.
124 */
125static void TemplateStateTxFree(void *state, uint64_t tx_id)
126{
127 TemplateState *echo = state;
128 TemplateTransaction *tx = NULL, *ttx;
129
130 SCLogNotice("Freeing transaction %"PRIu64, tx_id);
131
132 TAILQ_FOREACH_SAFE(tx, &echo->tx_list, next, ttx) {
133
134 /* Continue if this is not the transaction we are looking
135 * for. */
136 if (tx->tx_id != tx_id) {
137 continue;
138 }
139
140 /* Remove and free the transaction. */
141 TAILQ_REMOVE(&echo->tx_list, tx, next);
142 TemplateTxFree(tx);
143 return;
144 }
145
146 SCLogNotice("Transaction %"PRIu64" not found.", tx_id);
147}
148
149static int TemplateStateGetEventInfo(const char *event_name, int *event_id,
150 AppLayerEventType *event_type)
151{
152 *event_id = SCMapEnumNameToValue(event_name, template_decoder_event_table);
153 if (*event_id == -1) {
154 SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
155 "template enum map table.", event_name);
156 /* This should be treated as fatal. */
157 return -1;
158 }
159
160 *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
161
162 return 0;
163}
164
165static AppLayerDecoderEvents *TemplateGetEvents(void *state, uint64_t tx_id)
166{
167 TemplateState *template_state = state;
168 TemplateTransaction *tx;
169
170 TAILQ_FOREACH(tx, &template_state->tx_list, next) {
171 if (tx->tx_id == tx_id) {
172 return tx->decoder_events;
173 }
174 }
175
176 return NULL;
177}
178
179static int TemplateHasEvents(void *state)
180{
181 TemplateState *echo = state;
182 return echo->events;
183}
184
185/**
186 * \brief Probe the input to see if it looks like echo.
187 *
188 * \retval ALPROTO_TEMPLATE if it looks like echo, otherwise
189 * ALPROTO_UNKNOWN.
190 */
191static AppProto TemplateProbingParser(uint8_t *input, uint32_t input_len,
192 uint32_t *offset)
193{
194 /* Very simple test - if there is input, this is echo. */
195 if (input_len >= TEMPLATE_MIN_FRAME_LEN) {
196 SCLogNotice("Detected as ALPROTO_TEMPLATE.");
197 return ALPROTO_TEMPLATE;
198 }
199
200 SCLogNotice("Protocol not detected as ALPROTO_TEMPLATE.");
201 return ALPROTO_UNKNOWN;
202}
203
204static int TemplateParseRequest(Flow *f, void *state,
205 AppLayerParserState *pstate, uint8_t *input, uint32_t input_len,
206 void *local_data)
207{
208 TemplateState *echo = state;
209
210 SCLogNotice("Parsing echo request: len=%"PRIu32, input_len);
211
212 /* Likely connection closed, we can just return here. */
213 if ((input == NULL || input_len == 0) &&
214 AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
215 return 0;
216 }
217
218 /* Probably don't want to create a transaction in this case
219 * either. */
220 if (input == NULL || input_len == 0) {
221 return 0;
222 }
223
224 /* Normally you would parse out data here and store it in the
225 * transaction object, but as this is echo, we'll just record the
226 * request data. */
227
228 /* Also, if this protocol may have a "protocol data unit" span
229 * multiple chunks of data, which is always a possibility with
230 * TCP, you may need to do some buffering here.
231 *
232 * For the sake of simplicity, buffering is left out here, but
233 * even for an echo protocol we may want to buffer until a new
234 * line is seen, assuming its text based.
235 */
236
237 /* Allocate a transaction.
238 *
239 * But note that if a "protocol data unit" is not received in one
240 * chunk of data, and the buffering is done on the transaction, we
241 * may need to look for the transaction that this newly recieved
242 * data belongs to.
243 */
244 TemplateTransaction *tx = TemplateTxAlloc(echo);
245 if (unlikely(tx == NULL)) {
246 SCLogNotice("Failed to allocate new Template tx.");
247 goto end;
248 }
249 SCLogNotice("Allocated Template tx %"PRIu64".", tx->tx_id);
250
251 /* Make a copy of the request. */
252 tx->request_buffer = SCCalloc(1, input_len);
253 if (unlikely(tx->request_buffer == NULL)) {
254 goto end;
255 }
256 memcpy(tx->request_buffer, input, input_len);
257 tx->request_buffer_len = input_len;
258
259 /* Here we check for an empty message and create an app-layer
260 * event. */
261 if ((input_len == 1 && tx->request_buffer[0] == '\n') ||
262 (input_len == 2 && tx->request_buffer[0] == '\r')) {
263 SCLogNotice("Creating event for empty message.");
264 AppLayerDecoderEventsSetEventRaw(&tx->decoder_events,
265 TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE);
266 echo->events++;
267 }
268
269end:
270 return 0;
271}
272
273static int TemplateParseResponse(Flow *f, void *state, AppLayerParserState *pstate,
274 uint8_t *input, uint32_t input_len, void *local_data)
275{
276 TemplateState *echo = state;
277 TemplateTransaction *tx = NULL, *ttx;;
278
279 SCLogNotice("Parsing Template response.");
280
281 /* Likely connection closed, we can just return here. */
282 if ((input == NULL || input_len == 0) &&
283 AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
284 return 0;
285 }
286
287 /* Probably don't want to create a transaction in this case
288 * either. */
289 if (input == NULL || input_len == 0) {
290 return 0;
291 }
292
293 /* Look up the existing transaction for this response. In the case
294 * of echo, it will be the most recent transaction on the
295 * TemplateState object. */
296
297 /* We should just grab the last transaction, but this is to
298 * illustrate how you might traverse the transaction list to find
299 * the transaction associated with this response. */
300 TAILQ_FOREACH(ttx, &echo->tx_list, next) {
301 tx = ttx;
302 }
303
304 if (tx == NULL) {
305 SCLogNotice("Failed to find transaction for response on echo state %p.",
306 echo);
307 goto end;
308 }
309
310 SCLogNotice("Found transaction %"PRIu64" for response on echo state %p.",
311 tx->tx_id, echo);
312
313 /* If the protocol requires multiple chunks of data to complete, you may
314 * run into the case where you have existing response data.
315 *
316 * In this case, we just log that there is existing data and free it. But
317 * you might want to realloc the buffer and append the data.
318 */
319 if (tx->response_buffer != NULL) {
320 SCLogNotice("WARNING: Transaction already has response data, "
321 "existing data will be overwritten.");
322 SCFree(tx->response_buffer);
323 }
324
325 /* Make a copy of the response. */
326 tx->response_buffer = SCCalloc(1, input_len);
327 if (unlikely(tx->response_buffer == NULL)) {
328 goto end;
329 }
330 memcpy(tx->response_buffer, input, input_len);
331 tx->response_buffer_len = input_len;
332
333 /* Set the response_done flag for transaction state checking in
334 * TemplateGetStateProgress(). */
335 tx->response_done = 1;
336
337end:
338 return 0;
339}
340
341static uint64_t TemplateGetTxCnt(void *state)
342{
343 TemplateState *echo = state;
344 SCLogNotice("Current tx count is %"PRIu64".", echo->transaction_max);
345 return echo->transaction_max;
346}
347
348static void *TemplateGetTx(void *state, uint64_t tx_id)
349{
350 TemplateState *echo = state;
351 TemplateTransaction *tx;
352
353 SCLogNotice("Requested tx ID %"PRIu64".", tx_id);
354
355 TAILQ_FOREACH(tx, &echo->tx_list, next) {
356 if (tx->tx_id == tx_id) {
357 SCLogNotice("Transaction %"PRIu64" found, returning tx object %p.",
358 tx_id, tx);
359 return tx;
360 }
361 }
362
363 SCLogNotice("Transaction ID %"PRIu64" not found.", tx_id);
364 return NULL;
365}
366
4166ec30
MK
367static void TemplateSetTxLogged(void *state, void *vtx, uint32_t logger)
368{
369 TemplateTransaction *tx = (TemplateTransaction *)vtx;
370 tx->logged |= logger;
371}
372
373static int TemplateGetTxLogged(void *state, void *vtx, uint32_t logger)
374{
375 TemplateTransaction *tx = (TemplateTransaction *)vtx;
376 if (tx->logged & logger)
377 return 1;
378
379 return 0;
380}
381
c1b92126
JI
382/**
383 * \brief Called by the application layer.
384 *
385 * In most cases 1 can be returned here.
386 */
387static int TemplateGetAlstateProgressCompletionStatus(uint8_t direction) {
388 return 1;
389}
390
391/**
392 * \brief Return the state of a transaction in a given direction.
393 *
394 * In the case of the echo protocol, the existence of a transaction
395 * means that the request is done. However, some protocols that may
396 * need multiple chunks of data to complete the request may need more
397 * than just the existence of a transaction for the request to be
398 * considered complete.
399 *
400 * For the response to be considered done, the response for a request
401 * needs to be seen. The response_done flag is set on response for
402 * checking here.
403 */
404static int TemplateGetStateProgress(void *tx, uint8_t direction)
405{
406 TemplateTransaction *echotx = tx;
407
408 SCLogNotice("Transaction progress requested for tx ID %"PRIu64
409 ", direction=0x%02x", echotx->tx_id, direction);
410
411 if (direction & STREAM_TOCLIENT && echotx->response_done) {
412 return 1;
413 }
414 else if (direction & STREAM_TOSERVER) {
415 /* For echo, just the existence of the transaction means the
416 * request is done. */
417 return 1;
418 }
419
420 return 0;
421}
422
423/**
424 * \brief ???
425 */
426static DetectEngineState *TemplateGetTxDetectState(void *vtx)
427{
428 TemplateTransaction *tx = vtx;
429 return tx->de_state;
430}
431
432/**
433 * \brief ???
434 */
435static int TemplateSetTxDetectState(void *state, void *vtx,
436 DetectEngineState *s)
437{
438 TemplateTransaction *tx = vtx;
439 tx->de_state = s;
440 return 0;
441}
442
443void RegisterTemplateParsers(void)
444{
445 char *proto_name = "template";
446
9697a09d
JI
447 /* TEMPLATE_START_REMOVE */
448 if (ConfGetNode("app-layer.protocols.template") == NULL) {
449 return;
450 }
451 /* TEMPLATE_END_REMOVE */
452
c1b92126
JI
453 /* Check if Template TCP detection is enabled. If it does not exist in
454 * the configuration file then it will be enabled by default. */
455 if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
456
457 SCLogNotice("Template TCP protocol detection enabled.");
458
459 AppLayerProtoDetectRegisterProtocol(ALPROTO_TEMPLATE, proto_name);
460
461 if (RunmodeIsUnittests()) {
462
463 SCLogNotice("Unittest mode, registeringd default configuration.");
464 AppLayerProtoDetectPPRegister(IPPROTO_TCP, TEMPLATE_DEFAULT_PORT,
465 ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN, STREAM_TOSERVER,
466 TemplateProbingParser);
467
468 }
469 else {
470
471 if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP,
472 proto_name, ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN,
473 TemplateProbingParser)) {
474 SCLogNotice("No echo app-layer configuration, enabling echo"
475 " detection TCP detection on port %s.",
476 TEMPLATE_DEFAULT_PORT);
477 AppLayerProtoDetectPPRegister(IPPROTO_TCP,
478 TEMPLATE_DEFAULT_PORT, ALPROTO_TEMPLATE, 0,
479 TEMPLATE_MIN_FRAME_LEN, STREAM_TOSERVER,
480 TemplateProbingParser);
481 }
482
483 }
484
485 }
486
487 else {
488 SCLogNotice("Protocol detecter and parser disabled for Template.");
489 return;
490 }
491
492 if (AppLayerParserConfParserEnabled("udp", proto_name)) {
493
494 SCLogNotice("Registering Template protocol parser.");
495
496 /* Register functions for state allocation and freeing. A
497 * state is allocated for every new Template flow. */
498 AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_TEMPLATE,
499 TemplateStateAlloc, TemplateStateFree);
500
501 /* Register request parser for parsing frame from server to client. */
502 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEMPLATE,
503 STREAM_TOSERVER, TemplateParseRequest);
504
505 /* Register response parser for parsing frames from server to client. */
9697a09d
JI
506 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEMPLATE,
507 STREAM_TOCLIENT, TemplateParseResponse);
c1b92126
JI
508
509 /* Register a function to be called by the application layer
510 * when a transaction is to be freed. */
511 AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_TEMPLATE,
512 TemplateStateTxFree);
513
4166ec30
MK
514 AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_TEMPLATE,
515 TemplateGetTxLogged, TemplateSetTxLogged);
516
c1b92126 517 /* Register a function to return the current transaction count. */
9697a09d
JI
518 AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TEMPLATE,
519 TemplateGetTxCnt);
c1b92126
JI
520
521 /* Transaction handling. */
c4b918b6
MK
522 AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_TEMPLATE,
523 TemplateGetAlstateProgressCompletionStatus);
c1b92126
JI
524 AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP,
525 ALPROTO_TEMPLATE, TemplateGetStateProgress);
526 AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_TEMPLATE,
527 TemplateGetTx);
528
529 /* Application layer event handling. */
530 AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_TEMPLATE,
531 TemplateHasEvents);
532
533 /* What is this being registered for? */
534 AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_TEMPLATE,
535 NULL, TemplateGetTxDetectState, TemplateSetTxDetectState);
536
537 AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_TEMPLATE,
538 TemplateStateGetEventInfo);
539 AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_TEMPLATE,
540 TemplateGetEvents);
541 }
542 else {
543 SCLogNotice("Template protocol parsing disabled.");
544 }
545
546#ifdef UNITTESTS
547 AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_TEMPLATE,
548 TemplateParserRegisterTests);
549#endif
550}
551
552#ifdef UNITTESTS
553#endif
554
555void TemplateParserRegisterTests(void)
556{
557#ifdef UNITTESTS
558#endif
559}