]>
Commit | Line | Data |
---|---|---|
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 | */ | |
55 | enum { | |
56 | TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE, | |
57 | }; | |
58 | ||
59 | SCEnumCharMap template_decoder_event_table[] = { | |
60 | {"EMPTY_MESSAGE", TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE}, | |
61 | }; | |
62 | ||
63 | static 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 | ||
79 | static 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 | ||
96 | static 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 | ||
107 | static 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 | */ | |
125 | static 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 | ||
149 | static 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 | ||
165 | static 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 | ||
179 | static 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 | */ | |
191 | static 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 | ||
204 | static 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 | ||
269 | end: | |
270 | return 0; | |
271 | } | |
272 | ||
273 | static 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 | ||
337 | end: | |
338 | return 0; | |
339 | } | |
340 | ||
341 | static 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 | ||
348 | static 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 |
367 | static void TemplateSetTxLogged(void *state, void *vtx, uint32_t logger) |
368 | { | |
369 | TemplateTransaction *tx = (TemplateTransaction *)vtx; | |
370 | tx->logged |= logger; | |
371 | } | |
372 | ||
373 | static 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 | */ | |
387 | static 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 | */ | |
404 | static 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 | */ | |
426 | static DetectEngineState *TemplateGetTxDetectState(void *vtx) | |
427 | { | |
428 | TemplateTransaction *tx = vtx; | |
429 | return tx->de_state; | |
430 | } | |
431 | ||
432 | /** | |
433 | * \brief ??? | |
434 | */ | |
435 | static int TemplateSetTxDetectState(void *state, void *vtx, | |
436 | DetectEngineState *s) | |
437 | { | |
438 | TemplateTransaction *tx = vtx; | |
439 | tx->de_state = s; | |
440 | return 0; | |
441 | } | |
442 | ||
443 | void 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 | ||
555 | void TemplateParserRegisterTests(void) | |
556 | { | |
557 | #ifdef UNITTESTS | |
558 | #endif | |
559 | } |