]>
Commit | Line | Data |
---|---|---|
455eab37 | 1 | /* Copyright (C) 2015-2020 Open Information Security Foundation |
c1b92126 JI |
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 | ||
e878dd22 JI |
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 | ||
c1b92126 | 24 | /** |
e878dd22 JI |
25 | * \file |
26 | * | |
27 | * \author FirstName LastName <yourname@domain> | |
28 | * | |
29 | * Template application layer detector and parser for learning and | |
c1b92126 JI |
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" | |
9697a09d | 38 | #include "conf.h" |
c1b92126 JI |
39 | #include "app-layer-detect-proto.h" |
40 | #include "app-layer-parser.h" | |
c1b92126 JI |
41 | #include "app-layer-template.h" |
42 | ||
a013cece | 43 | #include "util-unittest.h" |
7476399f | 44 | #include "util-validate.h" |
a013cece | 45 | |
c1b92126 JI |
46 | /* The default port to probe for echo traffic if not provided in the |
47 | * configuration file. */ | |
48 | #define TEMPLATE_DEFAULT_PORT "7" | |
49 | ||
a013cece | 50 | /* The minimum size for a message. For some protocols this might |
c1b92126 JI |
51 | * be the size of a header. */ |
52 | #define TEMPLATE_MIN_FRAME_LEN 1 | |
53 | ||
a013cece | 54 | /* Enum of app-layer events for the protocol. Normally you might |
c1b92126 | 55 | * have events for errors in parsing data, like unexpected data being |
a013cece | 56 | * received. For template we'll make something up, and log an app-layer |
c1b92126 JI |
57 | * level alert if an empty message is received. |
58 | * | |
59 | * Example rule: | |
60 | * | |
3da79610 | 61 | * alert template any any -> any any (msg:"SURICATA Template empty message"; \ |
c1b92126 JI |
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}, | |
08e4908d PC |
70 | |
71 | // event table must be NULL-terminated | |
72 | { NULL, -1 }, | |
c1b92126 JI |
73 | }; |
74 | ||
a013cece | 75 | static TemplateTransaction *TemplateTxAlloc(TemplateState *state) |
c1b92126 JI |
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. */ | |
a013cece | 84 | tx->tx_id = state->transaction_max++; |
c1b92126 | 85 | |
a013cece | 86 | TAILQ_INSERT_TAIL(&state->tx_list, tx, next); |
c1b92126 JI |
87 | |
88 | return tx; | |
89 | } | |
90 | ||
a013cece | 91 | static void TemplateTxFree(void *txv) |
c1b92126 | 92 | { |
a013cece | 93 | TemplateTransaction *tx = txv; |
c1b92126 | 94 | |
a013cece VJ |
95 | if (tx->request_buffer != NULL) { |
96 | SCFree(tx->request_buffer); | |
c1b92126 JI |
97 | } |
98 | ||
a013cece VJ |
99 | if (tx->response_buffer != NULL) { |
100 | SCFree(tx->response_buffer); | |
c1b92126 JI |
101 | } |
102 | ||
a013cece | 103 | AppLayerDecoderEventsFreeEvents(&tx->decoder_events); |
c1b92126 JI |
104 | |
105 | SCFree(tx); | |
106 | } | |
107 | ||
547d6c2d | 108 | static void *TemplateStateAlloc(void *orig_state, AppProto proto_orig) |
c1b92126 JI |
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; | |
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 | */ | |
a013cece | 137 | static void TemplateStateTxFree(void *statev, uint64_t tx_id) |
c1b92126 | 138 | { |
a013cece | 139 | TemplateState *state = statev; |
c1b92126 JI |
140 | TemplateTransaction *tx = NULL, *ttx; |
141 | ||
142 | SCLogNotice("Freeing transaction %"PRIu64, tx_id); | |
143 | ||
a013cece | 144 | TAILQ_FOREACH_SAFE(tx, &state->tx_list, next, ttx) { |
c1b92126 JI |
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. */ | |
a013cece | 153 | TAILQ_REMOVE(&state->tx_list, tx, next); |
c1b92126 JI |
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, | |
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 | ||
50e23ba9 JL |
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 | ||
d568e7fa | 193 | static AppLayerDecoderEvents *TemplateGetEvents(void *tx) |
c1b92126 | 194 | { |
d568e7fa | 195 | return ((TemplateTransaction *)tx)->decoder_events; |
c1b92126 JI |
196 | } |
197 | ||
c1b92126 | 198 | /** |
5ff50773 | 199 | * \brief Probe the input to server to see if it looks like template. |
c1b92126 | 200 | * |
5ff50773 PA |
201 | * \retval ALPROTO_TEMPLATE if it looks like template, |
202 | * ALPROTO_FAILED, if it is clearly not ALPROTO_TEMPLATE, | |
203 | * otherwise ALPROTO_UNKNOWN. | |
c1b92126 | 204 | */ |
5ff50773 | 205 | static AppProto TemplateProbingParserTs(Flow *f, uint8_t direction, |
579cc9f0 | 206 | const uint8_t *input, uint32_t input_len, uint8_t *rdir) |
5ff50773 PA |
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, | |
579cc9f0 | 228 | const uint8_t *input, uint32_t input_len, uint8_t *rdir) |
c1b92126 | 229 | { |
a013cece | 230 | /* Very simple test - if there is input, this is template. */ |
c1b92126 JI |
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 | ||
44d3f264 | 240 | static AppLayerResult TemplateParseRequest(Flow *f, void *statev, |
579cc9f0 | 241 | AppLayerParserState *pstate, const uint8_t *input, uint32_t input_len, |
7bc3c3ac | 242 | void *local_data, const uint8_t flags) |
c1b92126 | 243 | { |
a013cece | 244 | TemplateState *state = statev; |
c1b92126 | 245 | |
a013cece | 246 | SCLogNotice("Parsing template request: len=%"PRIu32, input_len); |
c1b92126 | 247 | |
7476399f | 248 | if (input == NULL) { |
4f73943d | 249 | if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) { |
7476399f JI |
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); | |
c1b92126 JI |
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 | */ | |
a013cece | 286 | TemplateTransaction *tx = TemplateTxAlloc(state); |
c1b92126 JI |
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); | |
a013cece | 292 | |
c1b92126 JI |
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); | |
c1b92126 JI |
308 | } |
309 | ||
a013cece | 310 | end: |
44d3f264 | 311 | SCReturnStruct(APP_LAYER_OK); |
c1b92126 JI |
312 | } |
313 | ||
44d3f264 | 314 | static AppLayerResult TemplateParseResponse(Flow *f, void *statev, AppLayerParserState *pstate, |
579cc9f0 | 315 | const uint8_t *input, uint32_t input_len, void *local_data, |
7bc3c3ac | 316 | const uint8_t flags) |
c1b92126 | 317 | { |
a013cece VJ |
318 | TemplateState *state = statev; |
319 | TemplateTransaction *tx = NULL, *ttx; | |
c1b92126 JI |
320 | |
321 | SCLogNotice("Parsing Template response."); | |
322 | ||
323 | /* Likely connection closed, we can just return here. */ | |
324 | if ((input == NULL || input_len == 0) && | |
4f73943d | 325 | AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC)) { |
44d3f264 | 326 | SCReturnStruct(APP_LAYER_OK); |
c1b92126 JI |
327 | } |
328 | ||
329 | /* Probably don't want to create a transaction in this case | |
330 | * either. */ | |
331 | if (input == NULL || input_len == 0) { | |
44d3f264 | 332 | SCReturnStruct(APP_LAYER_OK); |
c1b92126 JI |
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. */ | |
a013cece | 342 | TAILQ_FOREACH(ttx, &state->tx_list, next) { |
c1b92126 JI |
343 | tx = ttx; |
344 | } | |
a013cece | 345 | |
c1b92126 | 346 | if (tx == NULL) { |
a013cece VJ |
347 | SCLogNotice("Failed to find transaction for response on state %p.", |
348 | state); | |
c1b92126 JI |
349 | goto end; |
350 | } | |
351 | ||
a013cece VJ |
352 | SCLogNotice("Found transaction %"PRIu64" for response on state %p.", |
353 | tx->tx_id, state); | |
c1b92126 JI |
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: | |
44d3f264 | 380 | SCReturnStruct(APP_LAYER_OK); |
c1b92126 JI |
381 | } |
382 | ||
a013cece | 383 | static uint64_t TemplateGetTxCnt(void *statev) |
c1b92126 | 384 | { |
a013cece VJ |
385 | const TemplateState *state = statev; |
386 | SCLogNotice("Current tx count is %"PRIu64".", state->transaction_max); | |
387 | return state->transaction_max; | |
c1b92126 JI |
388 | } |
389 | ||
a013cece | 390 | static void *TemplateGetTx(void *statev, uint64_t tx_id) |
c1b92126 | 391 | { |
a013cece | 392 | TemplateState *state = statev; |
c1b92126 JI |
393 | TemplateTransaction *tx; |
394 | ||
395 | SCLogNotice("Requested tx ID %"PRIu64".", tx_id); | |
396 | ||
a013cece | 397 | TAILQ_FOREACH(tx, &state->tx_list, next) { |
c1b92126 JI |
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 | */ | |
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 | */ | |
a013cece | 431 | static int TemplateGetStateProgress(void *txv, uint8_t direction) |
c1b92126 | 432 | { |
a013cece | 433 | TemplateTransaction *tx = txv; |
c1b92126 JI |
434 | |
435 | SCLogNotice("Transaction progress requested for tx ID %"PRIu64 | |
a013cece | 436 | ", direction=0x%02x", tx->tx_id, direction); |
c1b92126 | 437 | |
a013cece | 438 | if (direction & STREAM_TOCLIENT && tx->response_done) { |
c1b92126 JI |
439 | return 1; |
440 | } | |
441 | else if (direction & STREAM_TOSERVER) { | |
a013cece | 442 | /* For the template, just the existence of the transaction means the |
c1b92126 JI |
443 | * request is done. */ |
444 | return 1; | |
445 | } | |
446 | ||
447 | return 0; | |
448 | } | |
449 | ||
455eab37 VJ |
450 | /** |
451 | * \brief retrieve the tx data used for logging, config, detection | |
452 | */ | |
453 | static AppLayerTxData *TemplateGetTxData(void *vtx) | |
454 | { | |
455 | TemplateTransaction *tx = vtx; | |
456 | return &tx->tx_data; | |
457 | } | |
458 | ||
c1b92126 | 459 | /** |
a013cece | 460 | * \brief retrieve the detection engine per tx state |
c1b92126 JI |
461 | */ |
462 | static DetectEngineState *TemplateGetTxDetectState(void *vtx) | |
463 | { | |
464 | TemplateTransaction *tx = vtx; | |
465 | return tx->de_state; | |
466 | } | |
467 | ||
468 | /** | |
a013cece | 469 | * \brief get the detection engine per tx state |
c1b92126 | 470 | */ |
7548944b | 471 | static int TemplateSetTxDetectState(void *vtx, |
c1b92126 JI |
472 | DetectEngineState *s) |
473 | { | |
474 | TemplateTransaction *tx = vtx; | |
475 | tx->de_state = s; | |
476 | return 0; | |
477 | } | |
478 | ||
479 | void RegisterTemplateParsers(void) | |
480 | { | |
ab1200fb | 481 | const char *proto_name = "template"; |
c1b92126 | 482 | |
9697a09d JI |
483 | /* TEMPLATE_START_REMOVE */ |
484 | if (ConfGetNode("app-layer.protocols.template") == NULL) { | |
485 | return; | |
486 | } | |
487 | /* TEMPLATE_END_REMOVE */ | |
c1b92126 JI |
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, | |
5ff50773 | 501 | TemplateProbingParserTs, TemplateProbingParserTc); |
c1b92126 JI |
502 | |
503 | } | |
504 | else { | |
505 | ||
506 | if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, | |
507 | proto_name, ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN, | |
5ff50773 | 508 | TemplateProbingParserTs, TemplateProbingParserTc)) { |
a013cece | 509 | SCLogNotice("No template app-layer configuration, enabling echo" |
c1b92126 JI |
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, | |
5ff50773 | 515 | TemplateProbingParserTs, TemplateProbingParserTc); |
c1b92126 JI |
516 | } |
517 | ||
518 | } | |
519 | ||
520 | } | |
521 | ||
522 | else { | |
523 | SCLogNotice("Protocol detecter and parser disabled for Template."); | |
524 | return; | |
525 | } | |
526 | ||
a013cece | 527 | if (AppLayerParserConfParserEnabled("tcp", proto_name)) { |
c1b92126 JI |
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. */ | |
9697a09d JI |
541 | AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEMPLATE, |
542 | STREAM_TOCLIENT, TemplateParseResponse); | |
c1b92126 JI |
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. */ | |
9697a09d JI |
550 | AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TEMPLATE, |
551 | TemplateGetTxCnt); | |
c1b92126 JI |
552 | |
553 | /* Transaction handling. */ | |
c4b918b6 MK |
554 | AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_TEMPLATE, |
555 | TemplateGetAlstateProgressCompletionStatus); | |
c1b92126 JI |
556 | AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, |
557 | ALPROTO_TEMPLATE, TemplateGetStateProgress); | |
558 | AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_TEMPLATE, | |
559 | TemplateGetTx); | |
455eab37 VJ |
560 | AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_TEMPLATE, |
561 | TemplateGetTxData); | |
c1b92126 | 562 | |
c1b92126 JI |
563 | /* What is this being registered for? */ |
564 | AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_TEMPLATE, | |
7548944b | 565 | TemplateGetTxDetectState, TemplateSetTxDetectState); |
c1b92126 JI |
566 | |
567 | AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_TEMPLATE, | |
568 | TemplateStateGetEventInfo); | |
50e23ba9 JL |
569 | AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_TEMPLATE, |
570 | TemplateStateGetEventInfoById); | |
c1b92126 JI |
571 | AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_TEMPLATE, |
572 | TemplateGetEvents); | |
7476399f JI |
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); | |
c1b92126 JI |
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 | ||
592 | void TemplateParserRegisterTests(void) | |
593 | { | |
594 | #ifdef UNITTESTS | |
595 | #endif | |
596 | } |