]>
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 | |
c6a35d09 | 30 | * template purposes. |
c1b92126 JI |
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 | ||
7732efbe | 103 | AppLayerDecoderEventsFreeEvents(&tx->tx_data.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 | ||
c1b92126 | 193 | /** |
5ff50773 | 194 | * \brief Probe the input to server to see if it looks like template. |
c1b92126 | 195 | * |
5ff50773 PA |
196 | * \retval ALPROTO_TEMPLATE if it looks like template, |
197 | * ALPROTO_FAILED, if it is clearly not ALPROTO_TEMPLATE, | |
198 | * otherwise ALPROTO_UNKNOWN. | |
c1b92126 | 199 | */ |
5ff50773 | 200 | static AppProto TemplateProbingParserTs(Flow *f, uint8_t direction, |
579cc9f0 | 201 | const uint8_t *input, uint32_t input_len, uint8_t *rdir) |
5ff50773 PA |
202 | { |
203 | /* Very simple test - if there is input, this is template. */ | |
204 | if (input_len >= TEMPLATE_MIN_FRAME_LEN) { | |
205 | SCLogNotice("Detected as ALPROTO_TEMPLATE."); | |
206 | return ALPROTO_TEMPLATE; | |
207 | } | |
208 | ||
209 | SCLogNotice("Protocol not detected as ALPROTO_TEMPLATE."); | |
210 | return ALPROTO_UNKNOWN; | |
211 | } | |
212 | ||
213 | /** | |
214 | * \brief Probe the input to client to see if it looks like template. | |
215 | * TemplateProbingParserTs can be used instead if the protocol | |
216 | * is symmetric. | |
217 | * | |
218 | * \retval ALPROTO_TEMPLATE if it looks like template, | |
219 | * ALPROTO_FAILED, if it is clearly not ALPROTO_TEMPLATE, | |
220 | * otherwise ALPROTO_UNKNOWN. | |
221 | */ | |
222 | static AppProto TemplateProbingParserTc(Flow *f, uint8_t direction, | |
579cc9f0 | 223 | const uint8_t *input, uint32_t input_len, uint8_t *rdir) |
c1b92126 | 224 | { |
a013cece | 225 | /* Very simple test - if there is input, this is template. */ |
c1b92126 JI |
226 | if (input_len >= TEMPLATE_MIN_FRAME_LEN) { |
227 | SCLogNotice("Detected as ALPROTO_TEMPLATE."); | |
228 | return ALPROTO_TEMPLATE; | |
229 | } | |
230 | ||
231 | SCLogNotice("Protocol not detected as ALPROTO_TEMPLATE."); | |
232 | return ALPROTO_UNKNOWN; | |
233 | } | |
234 | ||
44d3f264 | 235 | static AppLayerResult TemplateParseRequest(Flow *f, void *statev, |
579cc9f0 | 236 | AppLayerParserState *pstate, const uint8_t *input, uint32_t input_len, |
7bc3c3ac | 237 | void *local_data, const uint8_t flags) |
c1b92126 | 238 | { |
a013cece | 239 | TemplateState *state = statev; |
c1b92126 | 240 | |
a013cece | 241 | SCLogNotice("Parsing template request: len=%"PRIu32, input_len); |
c1b92126 | 242 | |
7476399f | 243 | if (input == NULL) { |
4f73943d | 244 | if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) { |
7476399f JI |
245 | /* This is a signal that the stream is done. Do any |
246 | * cleanup if needed. Usually nothing is required here. */ | |
247 | SCReturnStruct(APP_LAYER_OK); | |
248 | } else if (flags & STREAM_GAP) { | |
249 | /* This is a signal that there has been a gap in the | |
250 | * stream. This only needs to be handled if gaps were | |
251 | * enabled during protocol registration. The input_len | |
252 | * contains the size of the gap. */ | |
253 | SCReturnStruct(APP_LAYER_OK); | |
254 | } | |
255 | /* This should not happen. If input is NULL, one of the above should be | |
256 | * true. */ | |
257 | DEBUG_VALIDATE_BUG_ON(true); | |
258 | SCReturnStruct(APP_LAYER_ERROR); | |
c1b92126 JI |
259 | } |
260 | ||
261 | /* Normally you would parse out data here and store it in the | |
262 | * transaction object, but as this is echo, we'll just record the | |
263 | * request data. */ | |
264 | ||
265 | /* Also, if this protocol may have a "protocol data unit" span | |
266 | * multiple chunks of data, which is always a possibility with | |
267 | * TCP, you may need to do some buffering here. | |
268 | * | |
269 | * For the sake of simplicity, buffering is left out here, but | |
270 | * even for an echo protocol we may want to buffer until a new | |
271 | * line is seen, assuming its text based. | |
272 | */ | |
273 | ||
274 | /* Allocate a transaction. | |
275 | * | |
276 | * But note that if a "protocol data unit" is not received in one | |
277 | * chunk of data, and the buffering is done on the transaction, we | |
c6a35d09 | 278 | * may need to look for the transaction that this newly received |
c1b92126 JI |
279 | * data belongs to. |
280 | */ | |
a013cece | 281 | TemplateTransaction *tx = TemplateTxAlloc(state); |
c1b92126 JI |
282 | if (unlikely(tx == NULL)) { |
283 | SCLogNotice("Failed to allocate new Template tx."); | |
284 | goto end; | |
285 | } | |
286 | SCLogNotice("Allocated Template tx %"PRIu64".", tx->tx_id); | |
a013cece | 287 | |
c1b92126 JI |
288 | /* Make a copy of the request. */ |
289 | tx->request_buffer = SCCalloc(1, input_len); | |
290 | if (unlikely(tx->request_buffer == NULL)) { | |
291 | goto end; | |
292 | } | |
293 | memcpy(tx->request_buffer, input, input_len); | |
294 | tx->request_buffer_len = input_len; | |
295 | ||
296 | /* Here we check for an empty message and create an app-layer | |
297 | * event. */ | |
298 | if ((input_len == 1 && tx->request_buffer[0] == '\n') || | |
299 | (input_len == 2 && tx->request_buffer[0] == '\r')) { | |
300 | SCLogNotice("Creating event for empty message."); | |
7732efbe | 301 | AppLayerDecoderEventsSetEventRaw(&tx->tx_data.events, TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE); |
c1b92126 JI |
302 | } |
303 | ||
a013cece | 304 | end: |
44d3f264 | 305 | SCReturnStruct(APP_LAYER_OK); |
c1b92126 JI |
306 | } |
307 | ||
44d3f264 | 308 | static AppLayerResult TemplateParseResponse(Flow *f, void *statev, AppLayerParserState *pstate, |
579cc9f0 | 309 | const uint8_t *input, uint32_t input_len, void *local_data, |
7bc3c3ac | 310 | const uint8_t flags) |
c1b92126 | 311 | { |
a013cece VJ |
312 | TemplateState *state = statev; |
313 | TemplateTransaction *tx = NULL, *ttx; | |
c1b92126 JI |
314 | |
315 | SCLogNotice("Parsing Template response."); | |
316 | ||
317 | /* Likely connection closed, we can just return here. */ | |
318 | if ((input == NULL || input_len == 0) && | |
4f73943d | 319 | AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC)) { |
44d3f264 | 320 | SCReturnStruct(APP_LAYER_OK); |
c1b92126 JI |
321 | } |
322 | ||
323 | /* Probably don't want to create a transaction in this case | |
324 | * either. */ | |
325 | if (input == NULL || input_len == 0) { | |
44d3f264 | 326 | SCReturnStruct(APP_LAYER_OK); |
c1b92126 JI |
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. */ | |
a013cece | 336 | TAILQ_FOREACH(ttx, &state->tx_list, next) { |
c1b92126 JI |
337 | tx = ttx; |
338 | } | |
a013cece | 339 | |
c1b92126 | 340 | if (tx == NULL) { |
a013cece VJ |
341 | SCLogNotice("Failed to find transaction for response on state %p.", |
342 | state); | |
c1b92126 JI |
343 | goto end; |
344 | } | |
345 | ||
a013cece VJ |
346 | SCLogNotice("Found transaction %"PRIu64" for response on state %p.", |
347 | tx->tx_id, state); | |
c1b92126 JI |
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: | |
44d3f264 | 374 | SCReturnStruct(APP_LAYER_OK); |
c1b92126 JI |
375 | } |
376 | ||
a013cece | 377 | static uint64_t TemplateGetTxCnt(void *statev) |
c1b92126 | 378 | { |
a013cece VJ |
379 | const TemplateState *state = statev; |
380 | SCLogNotice("Current tx count is %"PRIu64".", state->transaction_max); | |
381 | return state->transaction_max; | |
c1b92126 JI |
382 | } |
383 | ||
a013cece | 384 | static void *TemplateGetTx(void *statev, uint64_t tx_id) |
c1b92126 | 385 | { |
a013cece | 386 | TemplateState *state = statev; |
c1b92126 JI |
387 | TemplateTransaction *tx; |
388 | ||
389 | SCLogNotice("Requested tx ID %"PRIu64".", tx_id); | |
390 | ||
a013cece | 391 | TAILQ_FOREACH(tx, &state->tx_list, next) { |
c1b92126 JI |
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 | ||
c1b92126 JI |
403 | /** |
404 | * \brief Return the state of a transaction in a given direction. | |
405 | * | |
406 | * In the case of the echo protocol, the existence of a transaction | |
407 | * means that the request is done. However, some protocols that may | |
408 | * need multiple chunks of data to complete the request may need more | |
409 | * than just the existence of a transaction for the request to be | |
410 | * considered complete. | |
411 | * | |
412 | * For the response to be considered done, the response for a request | |
c6a35d09 | 413 | * needs to be seen. The response_done flag is set on response for |
c1b92126 JI |
414 | * checking here. |
415 | */ | |
a013cece | 416 | static int TemplateGetStateProgress(void *txv, uint8_t direction) |
c1b92126 | 417 | { |
a013cece | 418 | TemplateTransaction *tx = txv; |
c1b92126 JI |
419 | |
420 | SCLogNotice("Transaction progress requested for tx ID %"PRIu64 | |
a013cece | 421 | ", direction=0x%02x", tx->tx_id, direction); |
c1b92126 | 422 | |
a013cece | 423 | if (direction & STREAM_TOCLIENT && tx->response_done) { |
c1b92126 JI |
424 | return 1; |
425 | } | |
426 | else if (direction & STREAM_TOSERVER) { | |
a013cece | 427 | /* For the template, just the existence of the transaction means the |
c1b92126 JI |
428 | * request is done. */ |
429 | return 1; | |
430 | } | |
431 | ||
432 | return 0; | |
433 | } | |
434 | ||
455eab37 VJ |
435 | /** |
436 | * \brief retrieve the tx data used for logging, config, detection | |
437 | */ | |
438 | static AppLayerTxData *TemplateGetTxData(void *vtx) | |
439 | { | |
440 | TemplateTransaction *tx = vtx; | |
441 | return &tx->tx_data; | |
442 | } | |
443 | ||
c1b92126 JI |
444 | void RegisterTemplateParsers(void) |
445 | { | |
ab1200fb | 446 | const char *proto_name = "template"; |
c1b92126 JI |
447 | |
448 | /* Check if Template TCP detection is enabled. If it does not exist in | |
1f6a15cd JI |
449 | * the configuration file then it will be disabled by default. */ |
450 | if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("tcp", proto_name, false)) { | |
c1b92126 | 451 | |
1f6a15cd | 452 | SCLogDebug("Template TCP protocol detection enabled."); |
c1b92126 JI |
453 | |
454 | AppLayerProtoDetectRegisterProtocol(ALPROTO_TEMPLATE, proto_name); | |
455 | ||
456 | if (RunmodeIsUnittests()) { | |
457 | ||
c6a35d09 | 458 | SCLogNotice("Unittest mode, registering default configuration."); |
c1b92126 JI |
459 | AppLayerProtoDetectPPRegister(IPPROTO_TCP, TEMPLATE_DEFAULT_PORT, |
460 | ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN, STREAM_TOSERVER, | |
5ff50773 | 461 | TemplateProbingParserTs, TemplateProbingParserTc); |
c1b92126 JI |
462 | |
463 | } | |
464 | else { | |
465 | ||
466 | if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, | |
467 | proto_name, ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN, | |
5ff50773 | 468 | TemplateProbingParserTs, TemplateProbingParserTc)) { |
1f6a15cd JI |
469 | SCLogDebug("No template app-layer configuration, enabling echo" |
470 | " detection TCP detection on port %s.", | |
471 | TEMPLATE_DEFAULT_PORT); | |
c1b92126 JI |
472 | AppLayerProtoDetectPPRegister(IPPROTO_TCP, |
473 | TEMPLATE_DEFAULT_PORT, ALPROTO_TEMPLATE, 0, | |
474 | TEMPLATE_MIN_FRAME_LEN, STREAM_TOSERVER, | |
5ff50773 | 475 | TemplateProbingParserTs, TemplateProbingParserTc); |
c1b92126 JI |
476 | } |
477 | ||
478 | } | |
479 | ||
480 | } | |
481 | ||
482 | else { | |
1f6a15cd | 483 | SCLogDebug("Protocol detector and parser disabled for Template."); |
c1b92126 JI |
484 | return; |
485 | } | |
486 | ||
a013cece | 487 | if (AppLayerParserConfParserEnabled("tcp", proto_name)) { |
c1b92126 JI |
488 | |
489 | SCLogNotice("Registering Template protocol parser."); | |
490 | ||
491 | /* Register functions for state allocation and freeing. A | |
492 | * state is allocated for every new Template flow. */ | |
493 | AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_TEMPLATE, | |
494 | TemplateStateAlloc, TemplateStateFree); | |
495 | ||
496 | /* Register request parser for parsing frame from server to client. */ | |
497 | AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEMPLATE, | |
498 | STREAM_TOSERVER, TemplateParseRequest); | |
499 | ||
500 | /* Register response parser for parsing frames from server to client. */ | |
9697a09d JI |
501 | AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEMPLATE, |
502 | STREAM_TOCLIENT, TemplateParseResponse); | |
c1b92126 JI |
503 | |
504 | /* Register a function to be called by the application layer | |
505 | * when a transaction is to be freed. */ | |
506 | AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_TEMPLATE, | |
507 | TemplateStateTxFree); | |
508 | ||
509 | /* Register a function to return the current transaction count. */ | |
9697a09d JI |
510 | AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TEMPLATE, |
511 | TemplateGetTxCnt); | |
c1b92126 JI |
512 | |
513 | /* Transaction handling. */ | |
efc9a7a3 | 514 | AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_TEMPLATE, 1, 1); |
c1b92126 JI |
515 | AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, |
516 | ALPROTO_TEMPLATE, TemplateGetStateProgress); | |
517 | AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_TEMPLATE, | |
518 | TemplateGetTx); | |
455eab37 VJ |
519 | AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_TEMPLATE, |
520 | TemplateGetTxData); | |
c1b92126 | 521 | |
c1b92126 JI |
522 | AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_TEMPLATE, |
523 | TemplateStateGetEventInfo); | |
50e23ba9 JL |
524 | AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_TEMPLATE, |
525 | TemplateStateGetEventInfoById); | |
7476399f | 526 | |
c6a35d09 | 527 | /* Leave this is if your parser can handle gaps, otherwise |
7476399f JI |
528 | * remove. */ |
529 | AppLayerParserRegisterOptionFlags(IPPROTO_TCP, ALPROTO_TEMPLATE, | |
530 | APP_LAYER_PARSER_OPT_ACCEPT_GAPS); | |
c1b92126 JI |
531 | } |
532 | else { | |
1f6a15cd | 533 | SCLogDebug("Template protocol parsing disabled."); |
c1b92126 JI |
534 | } |
535 | ||
536 | #ifdef UNITTESTS | |
537 | AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_TEMPLATE, | |
538 | TemplateParserRegisterTests); | |
539 | #endif | |
540 | } | |
541 | ||
542 | #ifdef UNITTESTS | |
543 | #endif | |
544 | ||
545 | void TemplateParserRegisterTests(void) | |
546 | { | |
547 | #ifdef UNITTESTS | |
548 | #endif | |
549 | } |