]>
Commit | Line | Data |
---|---|---|
5532af46 | 1 | /* Copyright (C) 2007-2013 Open Information Security Foundation |
ce019275 WM |
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 | |
20 | * | |
21 | * \author Victor Julien <victor@inliniac.net> | |
22 | * | |
23 | * Generic App-layer parsing functions. | |
24 | */ | |
8e10844f | 25 | |
ecf86f9c | 26 | #include "suricata-common.h" |
8e10844f | 27 | #include "debug.h" |
c1e485cc | 28 | #include "util-unittest.h" |
8e10844f VJ |
29 | #include "decode.h" |
30 | #include "threads.h" | |
31 | ||
32 | #include "util-print.h" | |
33 | #include "util-pool.h" | |
34 | ||
cc76aa4b | 35 | #include "flow-util.h" |
429c6388 | 36 | #include "flow-private.h" |
cc76aa4b | 37 | |
0e4235cc | 38 | #include "detect-engine-state.h" |
d9686fae | 39 | #include "detect-engine-port.h" |
0e4235cc | 40 | |
6a53ab9c | 41 | #include "stream-tcp.h" |
8e10844f VJ |
42 | #include "stream-tcp-private.h" |
43 | #include "stream.h" | |
a16e7b74 | 44 | #include "stream-tcp-reassemble.h" |
8e10844f | 45 | |
e1022ee5 | 46 | #include "app-layer.h" |
8e10844f VJ |
47 | #include "app-layer-protos.h" |
48 | #include "app-layer-parser.h" | |
000ce98c | 49 | #include "app-layer-smb.h" |
9faa4b74 | 50 | #include "app-layer-smb2.h" |
000ce98c AS |
51 | #include "app-layer-dcerpc.h" |
52 | #include "app-layer-dcerpc-udp.h" | |
53 | #include "app-layer-htp.h" | |
54 | #include "app-layer-ftp.h" | |
55 | #include "app-layer-ssl.h" | |
56 | #include "app-layer-ssh.h" | |
576ec7da | 57 | #include "app-layer-smtp.h" |
8e01cba8 VJ |
58 | #include "app-layer-dns-udp.h" |
59 | #include "app-layer-dns-tcp.h" | |
8e10844f | 60 | |
ddde572f | 61 | #include "conf.h" |
705471e4 | 62 | #include "util-spm.h" |
9f78d47c | 63 | |
91bc83e5 | 64 | #include "util-debug.h" |
eea5ab4a | 65 | #include "decode-events.h" |
262a7300 | 66 | #include "util-unittest-helper.h" |
5ba41c78 | 67 | #include "util-validate.h" |
91bc83e5 | 68 | |
429c6388 | 69 | #include "runmodes.h" |
cae8e06c | 70 | |
72a16459 | 71 | typedef struct AppLayerParserThreadCtx_ { |
429c6388 | 72 | void *alproto_local_storage[FLOW_PROTO_MAX][ALPROTO_MAX]; |
72a16459 | 73 | } AppLayerParserThreadCtx; |
cae8e06c | 74 | |
b74c7330 | 75 | |
429c6388 AS |
76 | /** |
77 | * \brief App layer protocol parser context. | |
78 | */ | |
c23742a0 | 79 | typedef struct AppLayerParserProtoCtx_ |
429c6388 AS |
80 | { |
81 | /* 0 - to_server, 1 - to_client. */ | |
82 | int (*Parser[2])(Flow *f, void *protocol_state, | |
9634e60e | 83 | AppLayerParserState *pstate, |
429c6388 AS |
84 | uint8_t *input, uint32_t input_len, |
85 | void *local_storage); | |
86 | char logger; | |
87 | ||
88 | void *(*StateAlloc)(void); | |
89 | void (*StateFree)(void *); | |
90 | void (*StateTransactionFree)(void *, uint64_t); | |
91 | void *(*LocalStorageAlloc)(void); | |
92 | void (*LocalStorageFree)(void *); | |
93 | ||
94 | void (*Truncate)(void *, uint8_t); | |
95 | FileContainer *(*StateGetFiles)(void *, uint8_t); | |
96 | AppLayerDecoderEvents *(*StateGetEvents)(void *, uint64_t); | |
97 | int (*StateHasEvents)(void *); | |
98 | ||
99 | int (*StateGetProgress)(void *alstate, uint8_t direction); | |
100 | uint64_t (*StateGetTxCnt)(void *alstate); | |
101 | void *(*StateGetTx)(void *alstate, uint64_t tx_id); | |
102 | int (*StateGetProgressCompletionStatus)(uint8_t direction); | |
103 | int (*StateGetEventInfo)(const char *event_name, | |
104 | int *event_id, AppLayerEventType *event_type); | |
105 | ||
106 | /* Indicates the direction the parser is ready to see the data | |
107 | * the first time for a flow. Values accepted - | |
108 | * STREAM_TOSERVER, STREAM_TOCLIENT */ | |
109 | uint8_t first_data_dir; | |
e1022ee5 | 110 | |
429c6388 AS |
111 | #ifdef UNITTESTS |
112 | void (*RegisterUnittests)(void); | |
113 | #endif | |
c23742a0 | 114 | } AppLayerParserProtoCtx; |
429c6388 AS |
115 | |
116 | typedef struct AppLayerParserCtx_ { | |
c23742a0 | 117 | AppLayerParserProtoCtx ctxs[FLOW_PROTO_MAX][ALPROTO_MAX]; |
429c6388 AS |
118 | } AppLayerParserCtx; |
119 | ||
cd0627cd | 120 | typedef struct AppLayerParserState_ { |
429c6388 AS |
121 | uint8_t flags; |
122 | ||
123 | /* Indicates the current transaction that is being inspected. | |
124 | * We have a var per direction. */ | |
125 | uint64_t inspect_id[2]; | |
126 | /* Indicates the current transaction being logged. Unlike inspect_id, | |
127 | * we don't need a var per direction since we don't log a transaction | |
128 | * unless we have the entire transaction. */ | |
129 | uint64_t log_id; | |
130 | /* State version, incremented for each update. Can wrap around. */ | |
131 | uint16_t version; | |
132 | ||
133 | /* Used to store decoder events. */ | |
134 | AppLayerDecoderEvents *decoder_events; | |
cd0627cd | 135 | } AppLayerParserState; |
e1022ee5 | 136 | |
429c6388 AS |
137 | /* Static global version of the parser context. |
138 | * Post 2.0 let's look at changing this to move it out to app-layer.c. */ | |
139 | static AppLayerParserCtx alp_ctx; | |
5a9a23f9 | 140 | |
5cdeadb3 | 141 | static void AppLayerParserTransactionsCleanup(uint8_t ipproto, AppProto alproto, |
9634e60e | 142 | void *alstate, AppLayerParserState *parser_state_store) |
429c6388 | 143 | { |
9dc04d9f VJ |
144 | SCEnter(); |
145 | ||
429c6388 AS |
146 | uint64_t inspect = 0, log = 0; |
147 | uint64_t min; | |
c23742a0 | 148 | AppLayerParserProtoCtx *ctx = &alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]; |
429c6388 AS |
149 | |
150 | if (ctx->StateTransactionFree == NULL) | |
151 | goto end; | |
9dc04d9f | 152 | |
429c6388 AS |
153 | if (parser_state_store->inspect_id[0] < parser_state_store->inspect_id[1]) |
154 | inspect = parser_state_store->inspect_id[0]; | |
155 | else | |
156 | inspect = parser_state_store->inspect_id[1]; | |
157 | log = parser_state_store->log_id; | |
9dc04d9f | 158 | |
429c6388 AS |
159 | if (ctx->logger == TRUE) { |
160 | min = log < inspect ? log : inspect; | |
161 | if (min > 0) | |
162 | ctx->StateTransactionFree(alstate, min - 1); | |
9dc04d9f | 163 | } else { |
429c6388 AS |
164 | if (inspect > 0) |
165 | ctx->StateTransactionFree(alstate, inspect - 1); | |
9dc04d9f | 166 | } |
9dc04d9f | 167 | |
429c6388 AS |
168 | end: |
169 | SCReturn; | |
170 | } | |
e8ad876b | 171 | |
9634e60e | 172 | AppLayerParserState *AppLayerParserStateAlloc(void) |
429c6388 AS |
173 | { |
174 | SCEnter(); | |
9dc04d9f | 175 | |
cd0627cd | 176 | AppLayerParserState *pstate = (AppLayerParserState *)SCMalloc(sizeof(*pstate)); |
429c6388 AS |
177 | if (pstate == NULL) |
178 | goto end; | |
179 | memset(pstate, 0, sizeof(*pstate)); | |
9dc04d9f | 180 | |
429c6388 | 181 | end: |
9634e60e | 182 | SCReturnPtr(pstate, "AppLayerParserState"); |
9dc04d9f VJ |
183 | } |
184 | ||
9634e60e | 185 | void AppLayerParserStateFree(AppLayerParserState *pstate) |
429c6388 AS |
186 | { |
187 | SCEnter(); | |
188 | ||
9634e60e VJ |
189 | if (pstate->decoder_events != NULL) |
190 | AppLayerDecoderEventsFreeEvents(pstate->decoder_events); | |
429c6388 | 191 | SCFree(pstate); |
9dc04d9f | 192 | |
429c6388 | 193 | SCReturn; |
9dc04d9f VJ |
194 | } |
195 | ||
429c6388 | 196 | int AppLayerParserSetup(void) |
c1e485cc | 197 | { |
429c6388 | 198 | SCEnter(); |
fa079c1d | 199 | |
429c6388 | 200 | memset(&alp_ctx, 0, sizeof(alp_ctx)); |
5a9a23f9 | 201 | |
429c6388 | 202 | SCReturnInt(0); |
5a9a23f9 | 203 | } |
5a9a23f9 | 204 | |
429c6388 | 205 | int AppLayerParserDeSetup(void) |
d4d18e31 | 206 | { |
429c6388 | 207 | SCEnter(); |
d4d18e31 | 208 | |
429c6388 | 209 | SCReturnInt(0); |
d4d18e31 AS |
210 | } |
211 | ||
9634e60e | 212 | AppLayerParserThreadCtx *AppLayerParserThreadCtxAlloc(void) |
d4d18e31 | 213 | { |
429c6388 | 214 | SCEnter(); |
d4d18e31 | 215 | |
429c6388 AS |
216 | AppProto i = 0; |
217 | int j = 0; | |
72a16459 | 218 | AppLayerParserThreadCtx *tctx; |
d4d18e31 | 219 | |
429c6388 AS |
220 | tctx = SCMalloc(sizeof(*tctx)); |
221 | if (tctx == NULL) | |
222 | goto end; | |
223 | memset(tctx, 0, sizeof(*tctx)); | |
224 | ||
225 | for (i = 0; i < FLOW_PROTO_DEFAULT; i++) { | |
226 | for (j = 0; j < ALPROTO_MAX; j++) { | |
227 | tctx->alproto_local_storage[i][j] = | |
59327e0f | 228 | AppLayerParserGetProtocolParserLocalStorage(FlowGetReverseProtoMapping(i), j); |
429c6388 AS |
229 | } |
230 | } | |
231 | ||
232 | end: | |
233 | SCReturnPtr(tctx, "void *"); | |
d4d18e31 AS |
234 | } |
235 | ||
9634e60e | 236 | void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx) |
c1e485cc | 237 | { |
429c6388 | 238 | SCEnter(); |
9f78d47c | 239 | |
429c6388 AS |
240 | AppProto i = 0; |
241 | int j = 0; | |
429c6388 AS |
242 | |
243 | for (i = 0; i < FLOW_PROTO_DEFAULT; i++) { | |
244 | for (j = 0; j < ALPROTO_MAX; j++) { | |
245 | AppLayerParserDestroyProtocolParserLocalStorage(FlowGetReverseProtoMapping(i), | |
246 | j, | |
247 | tctx->alproto_local_storage[i][j]); | |
248 | } | |
9f78d47c | 249 | } |
cae8e06c | 250 | |
0bac43a1 | 251 | SCFree(tctx); |
429c6388 | 252 | SCReturn; |
9f78d47c VJ |
253 | } |
254 | ||
429c6388 AS |
255 | int AppLayerParserConfParserEnabled(const char *ipproto, |
256 | const char *alproto_name) | |
c1e485cc | 257 | { |
429c6388 AS |
258 | SCEnter(); |
259 | ||
260 | int enabled = 1; | |
261 | char param[100]; | |
262 | ConfNode *node; | |
263 | int r; | |
cae8e06c | 264 | |
429c6388 AS |
265 | if (RunmodeIsUnittests()) |
266 | goto enabled; | |
267 | ||
268 | r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.", | |
269 | alproto_name, ".enabled"); | |
270 | if (r < 0) { | |
271 | SCLogError(SC_ERR_FATAL, "snprintf failure."); | |
272 | exit(EXIT_FAILURE); | |
273 | } else if (r > (int)sizeof(param)) { | |
274 | SCLogError(SC_ERR_FATAL, "buffer not big enough to write param."); | |
275 | exit(EXIT_FAILURE); | |
4914d8d9 | 276 | } |
5a9a23f9 | 277 | |
429c6388 AS |
278 | node = ConfGetNode(param); |
279 | if (node == NULL) { | |
280 | SCLogDebug("Entry for %s not found.", param); | |
281 | r = snprintf(param, sizeof(param), "%s%s%s%s%s", "app-layer.protocols.", | |
282 | alproto_name, ".", ipproto, ".enabled"); | |
283 | if (r < 0) { | |
284 | SCLogError(SC_ERR_FATAL, "snprintf failure."); | |
285 | exit(EXIT_FAILURE); | |
286 | } else if (r > (int)sizeof(param)) { | |
287 | SCLogError(SC_ERR_FATAL, "buffer not big enough to write param."); | |
288 | exit(EXIT_FAILURE); | |
289 | } | |
290 | ||
291 | node = ConfGetNode(param); | |
292 | if (node == NULL) { | |
293 | SCLogDebug("Entry for %s not found.", param); | |
294 | goto enabled; | |
295 | } | |
9f78d47c | 296 | } |
9f78d47c | 297 | |
429c6388 AS |
298 | if (strcasecmp(node->val, "yes") == 0) { |
299 | goto enabled; | |
300 | } else if (strcasecmp(node->val, "no") == 0) { | |
301 | goto disabled; | |
302 | } else if (strcasecmp(node->val, "detection-only") == 0) { | |
303 | goto enabled; | |
9f78d47c | 304 | } else { |
429c6388 AS |
305 | SCLogError(SC_ERR_FATAL, "Invalid value found for %s.", param); |
306 | exit(EXIT_FAILURE); | |
9f78d47c | 307 | } |
429c6388 AS |
308 | |
309 | disabled: | |
310 | enabled = 0; | |
311 | enabled: | |
312 | SCReturnInt(enabled); | |
9f78d47c VJ |
313 | } |
314 | ||
429c6388 AS |
315 | /***** Parser related registration *****/ |
316 | ||
5cdeadb3 | 317 | int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
318 | uint8_t direction, |
319 | int (*Parser)(Flow *f, void *protocol_state, | |
9634e60e | 320 | AppLayerParserState *pstate, |
429c6388 AS |
321 | uint8_t *buf, uint32_t buf_len, |
322 | void *local_storage)) | |
c1e485cc | 323 | { |
574bcea0 VJ |
324 | SCEnter(); |
325 | ||
429c6388 AS |
326 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
327 | Parser[(direction & STREAM_TOSERVER) ? 0 : 1] = Parser; | |
9f78d47c | 328 | |
574bcea0 | 329 | SCReturnInt(0); |
9f78d47c VJ |
330 | } |
331 | ||
5cdeadb3 | 332 | void AppLayerParserRegisterParserAcceptableDataDirection(uint8_t ipproto, AppProto alproto, |
429c6388 | 333 | uint8_t direction) |
c13ad8c2 | 334 | { |
429c6388 AS |
335 | SCEnter(); |
336 | ||
337 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].first_data_dir |= | |
338 | (direction & (STREAM_TOSERVER | STREAM_TOCLIENT)); | |
339 | ||
340 | SCReturn; | |
c13ad8c2 AS |
341 | } |
342 | ||
5cdeadb3 | 343 | void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
344 | void *(*StateAlloc)(void), |
345 | void (*StateFree)(void *)) | |
c1e485cc | 346 | { |
574bcea0 VJ |
347 | SCEnter(); |
348 | ||
429c6388 AS |
349 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateAlloc = |
350 | StateAlloc; | |
351 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateFree = | |
352 | StateFree; | |
086ba5f4 | 353 | |
429c6388 AS |
354 | SCReturn; |
355 | } | |
086ba5f4 | 356 | |
5cdeadb3 | 357 | void AppLayerParserRegisterLocalStorageFunc(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
358 | void *(*LocalStorageAlloc)(void), |
359 | void (*LocalStorageFree)(void *)) | |
360 | { | |
361 | SCEnter(); | |
574bcea0 | 362 | |
429c6388 AS |
363 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].LocalStorageAlloc = |
364 | LocalStorageAlloc; | |
365 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].LocalStorageFree = | |
366 | LocalStorageFree; | |
086ba5f4 | 367 | |
429c6388 AS |
368 | SCReturn; |
369 | } | |
086ba5f4 | 370 | |
5cdeadb3 | 371 | void AppLayerParserRegisterGetFilesFunc(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
372 | FileContainer *(*StateGetFiles)(void *, uint8_t)) |
373 | { | |
374 | SCEnter(); | |
086ba5f4 | 375 | |
429c6388 AS |
376 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetFiles = |
377 | StateGetFiles; | |
086ba5f4 | 378 | |
429c6388 AS |
379 | SCReturn; |
380 | } | |
086ba5f4 | 381 | |
5cdeadb3 | 382 | void AppLayerParserRegisterGetEventsFunc(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
383 | AppLayerDecoderEvents *(*StateGetEvents)(void *, uint64_t)) |
384 | { | |
385 | SCEnter(); | |
574bcea0 | 386 | |
429c6388 AS |
387 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetEvents = |
388 | StateGetEvents; | |
086ba5f4 | 389 | |
429c6388 | 390 | SCReturn; |
086ba5f4 VJ |
391 | } |
392 | ||
5cdeadb3 | 393 | void AppLayerParserRegisterHasEventsFunc(uint8_t ipproto, AppProto alproto, |
429c6388 | 394 | int (*StateHasEvents)(void *)) |
c1e485cc | 395 | { |
574bcea0 | 396 | SCEnter(); |
574bcea0 | 397 | |
429c6388 AS |
398 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateHasEvents = |
399 | StateHasEvents; | |
574bcea0 | 400 | |
429c6388 AS |
401 | SCReturn; |
402 | } | |
574bcea0 | 403 | |
5cdeadb3 | 404 | void AppLayerParserRegisterLogger(uint8_t ipproto, AppProto alproto) |
429c6388 AS |
405 | { |
406 | SCEnter(); | |
9f78d47c | 407 | |
429c6388 | 408 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].logger = TRUE; |
9f78d47c | 409 | |
429c6388 AS |
410 | SCReturn; |
411 | } | |
9f78d47c | 412 | |
5cdeadb3 | 413 | void AppLayerParserRegisterTruncateFunc(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
414 | void (*Truncate)(void *, uint8_t)) |
415 | { | |
416 | SCEnter(); | |
574bcea0 | 417 | |
429c6388 | 418 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].Truncate = Truncate; |
574bcea0 | 419 | |
429c6388 AS |
420 | SCReturn; |
421 | } | |
9f78d47c | 422 | |
5cdeadb3 | 423 | void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
424 | int (*StateGetProgress)(void *alstate, uint8_t direction)) |
425 | { | |
426 | SCEnter(); | |
9f78d47c | 427 | |
429c6388 AS |
428 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
429 | StateGetProgress = StateGetProgress; | |
9f78d47c | 430 | |
429c6388 | 431 | SCReturn; |
9f78d47c VJ |
432 | } |
433 | ||
5cdeadb3 | 434 | void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, |
429c6388 | 435 | void (*StateTransactionFree)(void *, uint64_t)) |
c1e485cc | 436 | { |
574bcea0 | 437 | SCEnter(); |
9f78d47c | 438 | |
429c6388 AS |
439 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
440 | StateTransactionFree = StateTransactionFree; | |
9f78d47c | 441 | |
429c6388 AS |
442 | SCReturn; |
443 | } | |
9f78d47c | 444 | |
5cdeadb3 | 445 | void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
446 | uint64_t (*StateGetTxCnt)(void *alstate)) |
447 | { | |
448 | SCEnter(); | |
9f78d47c | 449 | |
429c6388 AS |
450 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
451 | StateGetTxCnt = StateGetTxCnt; | |
9f78d47c | 452 | |
429c6388 AS |
453 | SCReturn; |
454 | } | |
9f78d47c | 455 | |
5cdeadb3 | 456 | void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
457 | void *(StateGetTx)(void *alstate, uint64_t tx_id)) |
458 | { | |
459 | SCEnter(); | |
9f78d47c | 460 | |
429c6388 AS |
461 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
462 | StateGetTx = StateGetTx; | |
9f78d47c | 463 | |
429c6388 | 464 | SCReturn; |
9f78d47c VJ |
465 | } |
466 | ||
5cdeadb3 | 467 | void AppLayerParserRegisterGetStateProgressCompletionStatus(uint8_t ipproto, |
f5f14880 | 468 | AppProto alproto, |
429c6388 | 469 | int (*StateGetProgressCompletionStatus)(uint8_t direction)) |
c1e485cc | 470 | { |
429c6388 | 471 | SCEnter(); |
f1f7df07 | 472 | |
429c6388 AS |
473 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
474 | StateGetProgressCompletionStatus = StateGetProgressCompletionStatus; | |
f1f7df07 | 475 | |
429c6388 AS |
476 | SCReturn; |
477 | } | |
f1f7df07 | 478 | |
5cdeadb3 | 479 | void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
480 | int (*StateGetEventInfo)(const char *event_name, int *event_id, |
481 | AppLayerEventType *event_type)) | |
482 | { | |
483 | SCEnter(); | |
f1f7df07 | 484 | |
429c6388 AS |
485 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
486 | StateGetEventInfo = StateGetEventInfo; | |
d9686fae | 487 | |
429c6388 AS |
488 | SCReturn; |
489 | } | |
d9686fae | 490 | |
429c6388 | 491 | /***** Get and transaction functions *****/ |
d9686fae | 492 | |
5cdeadb3 | 493 | void *AppLayerParserGetProtocolParserLocalStorage(uint8_t ipproto, AppProto alproto) |
429c6388 AS |
494 | { |
495 | SCEnter(); | |
496 | ||
497 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
498 | LocalStorageAlloc != NULL) | |
499 | { | |
500 | SCReturnPtr(alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
501 | LocalStorageAlloc(), "void *"); | |
d9686fae AS |
502 | } |
503 | ||
429c6388 | 504 | SCReturnPtr(NULL, "void *"); |
f1f7df07 VJ |
505 | } |
506 | ||
5cdeadb3 | 507 | void AppLayerParserDestroyProtocolParserLocalStorage(uint8_t ipproto, AppProto alproto, |
429c6388 | 508 | void *local_data) |
68425453 | 509 | { |
429c6388 | 510 | SCEnter(); |
68425453 | 511 | |
429c6388 AS |
512 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
513 | LocalStorageFree != NULL) | |
514 | { | |
515 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
516 | LocalStorageFree(local_data); | |
68425453 EL |
517 | } |
518 | ||
429c6388 | 519 | SCReturn; |
68425453 EL |
520 | } |
521 | ||
9634e60e | 522 | uint64_t AppLayerParserGetTransactionLogId(AppLayerParserState *pstate) |
c1e485cc | 523 | { |
429c6388 | 524 | SCEnter(); |
8e10844f | 525 | |
9634e60e | 526 | SCReturnCT(pstate->log_id, "uint64_t"); |
429c6388 | 527 | } |
8e10844f | 528 | |
9634e60e | 529 | void AppLayerParserSetTransactionLogId(AppLayerParserState *pstate) |
429c6388 AS |
530 | { |
531 | SCEnter(); | |
5fc30051 | 532 | |
9634e60e | 533 | pstate->log_id++; |
5a9a23f9 | 534 | |
429c6388 | 535 | SCReturn; |
8e10844f VJ |
536 | } |
537 | ||
9634e60e | 538 | uint64_t AppLayerParserGetTransactionInspectId(AppLayerParserState *pstate, uint8_t direction) |
c1e485cc | 539 | { |
429c6388 | 540 | SCEnter(); |
8e10844f | 541 | |
9634e60e | 542 | SCReturnCT(pstate->inspect_id[direction & STREAM_TOSERVER ? 0 : 1], "uint64_t"); |
429c6388 | 543 | } |
5fc30051 | 544 | |
9634e60e | 545 | void AppLayerParserSetTransactionInspectId(AppLayerParserState *pstate, |
5cdeadb3 | 546 | uint8_t ipproto, AppProto alproto, void *alstate, |
429c6388 AS |
547 | uint8_t direction) |
548 | { | |
549 | SCEnter(); | |
59780ca7 | 550 | |
429c6388 AS |
551 | uint8_t dir = (direction & STREAM_TOSERVER) ? 0 : 1; |
552 | uint64_t total_txs = AppLayerParserGetTxCnt(ipproto, alproto, alstate); | |
553 | uint64_t idx = AppLayerParserGetTransactionInspectId(pstate, direction); | |
554 | int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(ipproto, alproto, direction); | |
555 | void *tx; | |
556 | int state_progress; | |
8e10844f | 557 | |
429c6388 AS |
558 | for (; idx < total_txs; idx++) { |
559 | tx = AppLayerParserGetTx(ipproto, alproto, alstate, idx); | |
560 | if (tx == NULL) | |
561 | continue; | |
562 | state_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx, direction); | |
563 | if (state_progress >= state_done_progress) | |
564 | continue; | |
565 | else | |
566 | break; | |
8e10844f | 567 | } |
9634e60e | 568 | pstate->inspect_id[dir] = idx; |
8e10844f | 569 | |
429c6388 | 570 | SCReturn; |
9faa4b74 | 571 | } |
9faa4b74 | 572 | |
9634e60e | 573 | AppLayerDecoderEvents *AppLayerParserGetDecoderEvents(AppLayerParserState *pstate) |
c1e485cc | 574 | { |
429c6388 | 575 | SCEnter(); |
9f78d47c | 576 | |
9634e60e | 577 | SCReturnPtr(pstate->decoder_events, |
429c6388 | 578 | "AppLayerDecoderEvents *"); |
70b32f73 VJ |
579 | } |
580 | ||
9634e60e | 581 | void AppLayerParserSetDecoderEvents(AppLayerParserState *pstate, AppLayerDecoderEvents *devents) |
9a6aef45 | 582 | { |
9634e60e | 583 | pstate->decoder_events = devents; |
9a6aef45 AS |
584 | } |
585 | ||
5cdeadb3 | 586 | AppLayerDecoderEvents *AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, |
429c6388 | 587 | void *alstate, uint64_t tx_id) |
869109a6 | 588 | { |
429c6388 | 589 | SCEnter(); |
869109a6 | 590 | |
429c6388 | 591 | AppLayerDecoderEvents *ptr = NULL; |
869109a6 | 592 | |
429c6388 AS |
593 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
594 | StateGetEvents != NULL) | |
595 | { | |
596 | ptr = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
597 | StateGetEvents(alstate, tx_id); | |
01a35bb6 AS |
598 | } |
599 | ||
429c6388 | 600 | SCReturnPtr(ptr, "AppLayerDecoderEvents *"); |
6cb00142 | 601 | } |
70b32f73 | 602 | |
9634e60e | 603 | uint16_t AppLayerParserGetStateVersion(AppLayerParserState *pstate) |
c1e485cc GS |
604 | { |
605 | SCEnter(); | |
9634e60e | 606 | SCReturnCT((pstate == NULL) ? 0 : pstate->version, "uint16_t"); |
9f78d47c VJ |
607 | } |
608 | ||
5cdeadb3 | 609 | FileContainer *AppLayerParserGetFiles(uint8_t ipproto, AppProto alproto, |
429c6388 | 610 | void *alstate, uint8_t direction) |
c1e485cc | 611 | { |
91bc83e5 | 612 | SCEnter(); |
8e10844f | 613 | |
429c6388 | 614 | FileContainer *ptr = NULL; |
45d86ff5 | 615 | |
429c6388 AS |
616 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
617 | StateGetFiles != NULL) | |
618 | { | |
619 | ptr = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
620 | StateGetFiles(alstate, direction); | |
3b3dce83 | 621 | } |
5ba41c78 | 622 | |
429c6388 | 623 | SCReturnPtr(ptr, "FileContainer *"); |
70b32f73 | 624 | } |
70b32f73 | 625 | |
5cdeadb3 | 626 | int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, |
429c6388 | 627 | void *alstate, uint8_t direction) |
d4d18e31 | 628 | { |
73efb4c7 | 629 | SCEnter(); |
429c6388 AS |
630 | SCReturnInt(alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
631 | StateGetProgress(alstate, direction)); | |
d4d18e31 | 632 | } |
70b32f73 | 633 | |
5cdeadb3 | 634 | uint64_t AppLayerParserGetTxCnt(uint8_t ipproto, AppProto alproto, void *alstate) |
d4d18e31 | 635 | { |
16cfae2f | 636 | SCEnter(); |
429c6388 AS |
637 | SCReturnCT(alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
638 | StateGetTxCnt(alstate), "uint64_t"); | |
16cfae2f VJ |
639 | } |
640 | ||
5cdeadb3 | 641 | void *AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id) |
ddde572f | 642 | { |
429c6388 AS |
643 | SCEnter(); |
644 | SCReturnPtr(alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
645 | StateGetTx(alstate, tx_id), "void *"); | |
ddde572f AS |
646 | } |
647 | ||
5cdeadb3 | 648 | int AppLayerParserGetStateProgressCompletionStatus(uint8_t ipproto, AppProto alproto, |
429c6388 | 649 | uint8_t direction) |
6cb00142 | 650 | { |
429c6388 AS |
651 | SCEnter(); |
652 | SCReturnInt(alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
653 | StateGetProgressCompletionStatus(direction)); | |
6cb00142 | 654 | |
6cb00142 AS |
655 | } |
656 | ||
5cdeadb3 | 657 | int AppLayerParserGetEventInfo(uint8_t ipproto, AppProto alproto, const char *event_name, |
429c6388 | 658 | int *event_id, AppLayerEventType *event_type) |
6f8cfd99 | 659 | { |
429c6388 AS |
660 | SCEnter(); |
661 | int ipproto_map = FlowGetProtoMapping(ipproto); | |
1cbd1cdf VJ |
662 | int r = (alp_ctx.ctxs[ipproto_map][alproto].StateGetEventInfo == NULL) ? |
663 | -1 : alp_ctx.ctxs[ipproto_map][alproto].StateGetEventInfo(event_name, event_id, event_type); | |
664 | SCReturnInt(r); | |
6f8cfd99 AS |
665 | } |
666 | ||
f5f14880 | 667 | uint8_t AppLayerParserGetFirstDataDir(uint8_t ipproto, AppProto alproto) |
432c3317 | 668 | { |
429c6388 AS |
669 | SCEnter(); |
670 | SCReturnCT(alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
671 | first_data_dir, "uint8_t"); | |
432c3317 | 672 | } |
7c31a232 | 673 | |
9634e60e VJ |
674 | uint64_t AppLayerParserGetTransactionActive(uint8_t ipproto, AppProto alproto, |
675 | AppLayerParserState *pstate, uint8_t direction) | |
d9686fae | 676 | { |
429c6388 | 677 | SCEnter(); |
d9686fae | 678 | |
429c6388 | 679 | uint64_t active_id; |
d9686fae | 680 | |
9634e60e VJ |
681 | uint64_t log_id = pstate->log_id; |
682 | uint64_t inspect_id = pstate->inspect_id[direction & STREAM_TOSERVER ? 0 : 1]; | |
429c6388 AS |
683 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].logger == TRUE) { |
684 | active_id = (log_id < inspect_id) ? log_id : inspect_id; | |
685 | } else { | |
686 | active_id = inspect_id; | |
d9686fae | 687 | } |
d9686fae | 688 | |
429c6388 | 689 | SCReturnCT(active_id, "uint64_t"); |
d9686fae AS |
690 | } |
691 | ||
429c6388 AS |
692 | /***** General *****/ |
693 | ||
9634e60e | 694 | int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, |
429c6388 | 695 | uint8_t flags, uint8_t *input, uint32_t input_len) |
d9686fae | 696 | { |
429c6388 | 697 | SCEnter(); |
d9686fae | 698 | |
cd0627cd | 699 | AppLayerParserState *pstate = NULL; |
c23742a0 | 700 | AppLayerParserProtoCtx *p = &alp_ctx.ctxs[FlowGetProtoMapping(f->proto)][alproto]; |
429c6388 AS |
701 | TcpSession *ssn = NULL; |
702 | void *alstate = NULL; | |
d9686fae | 703 | |
429c6388 AS |
704 | /* we don't have the parser registered for this protocol */ |
705 | if (p->StateAlloc == NULL) | |
706 | goto end; | |
d9686fae | 707 | |
429c6388 AS |
708 | /* Used only if it's TCP */ |
709 | ssn = f->protoctx; | |
d9686fae | 710 | |
429c6388 AS |
711 | /* Do this check before calling AppLayerParse */ |
712 | if (flags & STREAM_GAP) { | |
713 | SCLogDebug("stream gap detected (missing packets), " | |
714 | "this is not yet supported."); | |
d9686fae | 715 | |
429c6388 AS |
716 | if (f->alstate != NULL) |
717 | AppLayerParserStreamTruncated(f->proto, alproto, f->alstate, flags); | |
718 | goto error; | |
d9686fae | 719 | } |
d9686fae | 720 | |
429c6388 AS |
721 | /* Get the parser state (if any) */ |
722 | pstate = f->alparser; | |
723 | if (pstate == NULL) { | |
8527b8e0 | 724 | f->alparser = pstate = AppLayerParserStateAlloc(); |
429c6388 AS |
725 | if (pstate == NULL) |
726 | goto error; | |
d9686fae | 727 | } |
429c6388 AS |
728 | pstate->version++; |
729 | SCLogDebug("app layer parser state version incremented to %"PRIu16, | |
730 | pstate->version); | |
d9686fae | 731 | |
429c6388 | 732 | if (flags & STREAM_EOF) |
8527b8e0 | 733 | AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_EOF); |
7c31a232 | 734 | |
429c6388 AS |
735 | alstate = f->alstate; |
736 | if (alstate == NULL) { | |
737 | f->alstate = alstate = p->StateAlloc(); | |
738 | if (alstate == NULL) | |
739 | goto error; | |
740 | SCLogDebug("alloced new app layer state %p (name %s)", | |
741 | alstate, AppLayerGetProtoName(f->alproto)); | |
742 | } else { | |
743 | SCLogDebug("using existing app layer state %p (name %s))", | |
744 | alstate, AppLayerGetProtoName(f->alproto)); | |
6e0d98d9 | 745 | } |
429c6388 AS |
746 | |
747 | /* invoke the recursive parser, but only on data. We may get empty msgs on EOF */ | |
748 | if (input_len > 0) { | |
749 | /* invoke the parser */ | |
750 | if (p->Parser[(flags & STREAM_TOSERVER) ? 0 : 1](f, alstate, pstate, | |
751 | input, input_len, | |
752 | alp_tctx->alproto_local_storage[FlowGetProtoMapping(f->proto)][alproto]) < 0) | |
59327e0f VJ |
753 | { |
754 | goto error; | |
755 | } | |
6e0d98d9 | 756 | } |
429c6388 AS |
757 | |
758 | /* set the packets to no inspection and reassembly if required */ | |
759 | if (pstate->flags & APP_LAYER_PARSER_NO_INSPECTION) { | |
760 | AppLayerParserSetEOF(pstate); | |
761 | FlowSetNoPayloadInspectionFlag(f); | |
762 | FlowSetSessionNoApplayerInspectionFlag(f); | |
763 | ||
764 | /* Set the no reassembly flag for both the stream in this TcpSession */ | |
765 | if (pstate->flags & APP_LAYER_PARSER_NO_REASSEMBLY) { | |
766 | if (ssn != NULL) { | |
767 | StreamTcpSetSessionNoReassemblyFlag(ssn, | |
768 | flags & STREAM_TOCLIENT ? 1 : 0); | |
769 | StreamTcpSetSessionNoReassemblyFlag(ssn, | |
770 | flags & STREAM_TOSERVER ? 1 : 0); | |
771 | } | |
772 | } | |
7f8fb0f0 AS |
773 | } |
774 | ||
429c6388 AS |
775 | /* next, see if we can get rid of transactions now */ |
776 | AppLayerParserTransactionsCleanup(f->proto, alproto, alstate, pstate); | |
777 | ||
778 | /* stream truncated, inform app layer */ | |
779 | if (flags & STREAM_DEPTH) | |
780 | AppLayerParserStreamTruncated(f->proto, alproto, alstate, flags); | |
781 | ||
782 | end: | |
783 | SCReturnInt(0); | |
6e0d98d9 | 784 | error: |
429c6388 AS |
785 | if (ssn != NULL) { |
786 | /* Set the no app layer inspection flag for both | |
787 | * the stream in this Flow */ | |
788 | FlowSetSessionNoApplayerInspectionFlag(f); | |
789 | AppLayerParserSetEOF(pstate); | |
790 | } | |
791 | SCReturnInt(-1); | |
7c31a232 AS |
792 | } |
793 | ||
9634e60e | 794 | void AppLayerParserSetEOF(AppLayerParserState *pstate) |
7c31a232 | 795 | { |
429c6388 | 796 | SCEnter(); |
7c31a232 | 797 | |
429c6388 AS |
798 | if (pstate == NULL) |
799 | goto end; | |
800 | ||
8527b8e0 | 801 | AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_EOF); |
429c6388 AS |
802 | /* increase version so we will inspect it one more time |
803 | * with the EOF flags now set */ | |
9634e60e | 804 | pstate->version++; |
429c6388 AS |
805 | |
806 | end: | |
807 | SCReturn; | |
432c3317 AS |
808 | } |
809 | ||
5cdeadb3 | 810 | int AppLayerParserHasDecoderEvents(uint8_t ipproto, AppProto alproto, |
9634e60e | 811 | void *alstate, AppLayerParserState *pstate, |
429c6388 | 812 | uint8_t flags) |
432c3317 | 813 | { |
429c6388 | 814 | SCEnter(); |
432c3317 | 815 | |
429c6388 AS |
816 | if (alstate == NULL || pstate == NULL) |
817 | goto not_present; | |
7c31a232 | 818 | |
429c6388 AS |
819 | AppLayerDecoderEvents *decoder_events; |
820 | uint64_t tx_id; | |
821 | uint64_t max_id; | |
822 | ||
823 | if (AppLayerParserProtocolIsTxEventAware(ipproto, alproto)) { | |
824 | /* fast path if supported by alproto */ | |
825 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateHasEvents != NULL) { | |
826 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
827 | StateHasEvents(alstate) == 1) | |
828 | { | |
829 | goto present; | |
d9686fae | 830 | } |
429c6388 AS |
831 | } else { |
832 | /* check each tx */ | |
833 | tx_id = AppLayerParserGetTransactionInspectId(pstate, flags); | |
834 | max_id = AppLayerParserGetTxCnt(ipproto, alproto, alstate); | |
835 | for ( ; tx_id < max_id; tx_id++) { | |
836 | decoder_events = AppLayerParserGetEventsByTx(ipproto, alproto, alstate, tx_id); | |
837 | if (decoder_events && decoder_events->cnt) | |
838 | goto present; | |
7c31a232 | 839 | } |
7c31a232 | 840 | } |
7c31a232 AS |
841 | } |
842 | ||
429c6388 AS |
843 | decoder_events = AppLayerParserGetDecoderEvents(pstate); |
844 | if (decoder_events && decoder_events->cnt) | |
845 | goto present; | |
846 | ||
847 | /* if we have reached here, we don't have events */ | |
848 | not_present: | |
849 | SCReturnInt(0); | |
850 | present: | |
851 | SCReturnInt(1); | |
d9686fae AS |
852 | } |
853 | ||
5cdeadb3 | 854 | int AppLayerParserProtocolIsTxEventAware(uint8_t ipproto, AppProto alproto) |
d9686fae | 855 | { |
429c6388 AS |
856 | SCEnter(); |
857 | int ipproto_map = FlowGetProtoMapping(ipproto); | |
1cbd1cdf VJ |
858 | int r = (alp_ctx.ctxs[ipproto_map][alproto].StateHasEvents == NULL) ? 0 : 1; |
859 | SCReturnInt(r); | |
429c6388 | 860 | } |
432c3317 | 861 | |
5cdeadb3 | 862 | int AppLayerParserProtocolSupportsTxs(uint8_t ipproto, AppProto alproto) |
429c6388 AS |
863 | { |
864 | SCEnter(); | |
865 | int ipproto_map = FlowGetProtoMapping(ipproto); | |
1cbd1cdf VJ |
866 | int r = (alp_ctx.ctxs[ipproto_map][alproto].StateTransactionFree == NULL) ? 0 : 1; |
867 | SCReturnInt(r); | |
432c3317 AS |
868 | } |
869 | ||
429c6388 | 870 | void AppLayerParserTriggerRawStreamReassembly(Flow *f) |
432c3317 | 871 | { |
429c6388 | 872 | SCEnter(); |
432c3317 | 873 | |
429c6388 AS |
874 | if (f != NULL && f->protoctx != NULL) |
875 | StreamTcpReassembleTriggerRawReassembly(f->protoctx); | |
d9686fae | 876 | |
429c6388 | 877 | SCReturn; |
7c31a232 AS |
878 | } |
879 | ||
429c6388 AS |
880 | /***** Cleanup *****/ |
881 | ||
9634e60e VJ |
882 | void AppLayerParserStateCleanup(uint8_t ipproto, AppProto alproto, void *alstate, |
883 | AppLayerParserState *pstate) | |
7c31a232 | 884 | { |
429c6388 | 885 | SCEnter(); |
7c31a232 | 886 | |
c23742a0 | 887 | AppLayerParserProtoCtx *ctx = &alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]; |
7c31a232 | 888 | |
429c6388 AS |
889 | if (ctx->StateFree != NULL && alstate != NULL) |
890 | ctx->StateFree(alstate); | |
7c31a232 | 891 | |
429c6388 AS |
892 | /* free the app layer parser api state */ |
893 | if (pstate != NULL) | |
8527b8e0 | 894 | AppLayerParserStateFree(pstate); |
432c3317 | 895 | |
429c6388 AS |
896 | SCReturn; |
897 | } | |
432c3317 | 898 | |
432c3317 | 899 | |
429c6388 AS |
900 | void AppLayerParserRegisterProtocolParsers(void) |
901 | { | |
902 | SCEnter(); | |
d9686fae | 903 | |
429c6388 AS |
904 | RegisterHTPParsers(); |
905 | RegisterSSLParsers(); | |
906 | RegisterSMBParsers(); | |
907 | /** \todo bug 719 */ | |
908 | //RegisterSMB2Parsers(); | |
909 | RegisterDCERPCParsers(); | |
910 | RegisterDCERPCUDPParsers(); | |
911 | RegisterFTPParsers(); | |
912 | /* we are disabling the ssh parser temporarily, since we are moving away | |
913 | * from some of the archaic features we use in the app layer. We will | |
914 | * reintroduce this parser. Also do note that keywords that rely on | |
915 | * the ssh parser would now be disabled */ | |
916 | #if 0 | |
917 | RegisterSSHParsers(); | |
918 | #endif | |
919 | RegisterSMTPParsers(); | |
920 | RegisterDNSUDPParsers(); | |
921 | RegisterDNSTCPParsers(); | |
432c3317 | 922 | |
429c6388 AS |
923 | /** IMAP */ |
924 | AppLayerProtoDetectRegisterProtocol(ALPROTO_IMAP, "imap"); | |
925 | if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", "imap")) { | |
926 | if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_IMAP, | |
927 | "1|20|capability", 12, 0, STREAM_TOSERVER) < 0) | |
928 | { | |
929 | SCLogInfo("imap proto registration failure\n"); | |
930 | exit(EXIT_FAILURE); | |
d9686fae | 931 | } |
429c6388 AS |
932 | } else { |
933 | SCLogInfo("Protocol detection and parser disabled for %s protocol.", | |
934 | "imap"); | |
d9686fae | 935 | } |
429c6388 AS |
936 | |
937 | /** MSN Messenger */ | |
938 | AppLayerProtoDetectRegisterProtocol(ALPROTO_MSN, "msn"); | |
939 | if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", "msn")) { | |
940 | if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_MSN, | |
941 | "msn", 10, 6, STREAM_TOSERVER) < 0) | |
942 | { | |
943 | SCLogInfo("msn proto registration failure\n"); | |
944 | exit(EXIT_FAILURE); | |
7c31a232 | 945 | } |
d9686fae | 946 | } else { |
429c6388 AS |
947 | SCLogInfo("Protocol detection and parser disabled for %s protocol.", |
948 | "msn"); | |
7c31a232 | 949 | } |
432c3317 | 950 | |
432c3317 AS |
951 | return; |
952 | } | |
953 | ||
0d7159b5 | 954 | |
9634e60e | 955 | void AppLayerParserStateSetFlag(AppLayerParserState *pstate, uint8_t flag) |
429c6388 AS |
956 | { |
957 | SCEnter(); | |
9634e60e | 958 | pstate->flags |= flag; |
429c6388 | 959 | SCReturn; |
0d7159b5 AS |
960 | } |
961 | ||
9634e60e | 962 | int AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint8_t flag) |
0d7159b5 | 963 | { |
429c6388 | 964 | SCEnter(); |
9634e60e | 965 | SCReturnInt(pstate->flags & flag); |
0d7159b5 AS |
966 | } |
967 | ||
429c6388 | 968 | |
5cdeadb3 | 969 | void AppLayerParserStreamTruncated(uint8_t ipproto, AppProto alproto, void *alstate, |
429c6388 | 970 | uint8_t direction) |
d9686fae | 971 | { |
429c6388 | 972 | SCEnter(); |
432c3317 | 973 | |
429c6388 AS |
974 | |
975 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].Truncate != NULL) | |
976 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].Truncate(alstate, direction); | |
977 | ||
978 | SCReturn; | |
7c31a232 AS |
979 | } |
980 | ||
429c6388 | 981 | #ifdef DEBUG |
9634e60e | 982 | void AppLayerParserStatePrintDetails(AppLayerParserState *pstate) |
7c31a232 | 983 | { |
429c6388 | 984 | SCEnter(); |
980934d6 | 985 | |
429c6388 AS |
986 | if (pstate == NULL) |
987 | SCReturn; | |
7c31a232 | 988 | |
9634e60e | 989 | AppLayerParserState *p = pstate; |
429c6388 AS |
990 | SCLogDebug("AppLayerParser parser state information for parser state p(%p). " |
991 | "p->inspect_id[0](%"PRIu64"), " | |
992 | "p->inspect_id[1](%"PRIu64"), " | |
993 | "p->log_id(%"PRIu64"), " | |
994 | "p->version(%"PRIu16"), " | |
995 | "p->decoder_events(%p).", | |
996 | pstate, p->inspect_id[0], p->inspect_id[1], p->log_id, | |
997 | p->version, p->decoder_events); | |
7c31a232 | 998 | |
429c6388 | 999 | SCReturn; |
7c31a232 | 1000 | } |
429c6388 AS |
1001 | #endif |
1002 | ||
7c31a232 | 1003 | |
429c6388 | 1004 | /***** Unittests *****/ |
7c31a232 | 1005 | |
c1e485cc GS |
1006 | #ifdef UNITTESTS |
1007 | ||
429c6388 AS |
1008 | static AppLayerParserCtx alp_ctx_backup_unittest; |
1009 | ||
c1e485cc GS |
1010 | typedef struct TestState_ { |
1011 | uint8_t test; | |
429c6388 | 1012 | } TestState; |
c1e485cc GS |
1013 | |
1014 | /** | |
1015 | * \brief Test parser function to test the memory deallocation of app layer | |
1016 | * parser of occurence of an error. | |
1017 | */ | |
9634e60e | 1018 | static int TestProtocolParser(Flow *f, void *test_state, AppLayerParserState *pstate, |
9a6aef45 | 1019 | uint8_t *input, uint32_t input_len, |
429c6388 | 1020 | void *local_data) |
c1e485cc | 1021 | { |
429c6388 AS |
1022 | SCEnter(); |
1023 | SCReturnInt(-1); | |
c1e485cc GS |
1024 | } |
1025 | ||
1026 | /** \brief Function to allocates the Test protocol state memory | |
1027 | */ | |
1028 | static void *TestProtocolStateAlloc(void) | |
1029 | { | |
429c6388 | 1030 | SCEnter(); |
25a3a5c6 | 1031 | void *s = SCMalloc(sizeof(TestState)); |
e176be6f | 1032 | if (unlikely(s == NULL)) |
429c6388 | 1033 | goto end; |
c1e485cc | 1034 | memset(s, 0, sizeof(TestState)); |
429c6388 AS |
1035 | end: |
1036 | SCReturnPtr(s, "TestState"); | |
c1e485cc GS |
1037 | } |
1038 | ||
1039 | /** \brief Function to free the Test Protocol state memory | |
1040 | */ | |
1041 | static void TestProtocolStateFree(void *s) | |
1042 | { | |
25a3a5c6 | 1043 | SCFree(s); |
c1e485cc GS |
1044 | } |
1045 | ||
5cdeadb3 | 1046 | void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, |
429c6388 | 1047 | void (*RegisterUnittests)(void)) |
6cb00142 | 1048 | { |
429c6388 AS |
1049 | SCEnter(); |
1050 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
1051 | RegisterUnittests = RegisterUnittests; | |
1052 | SCReturn; | |
6cb00142 AS |
1053 | } |
1054 | ||
429c6388 | 1055 | void AppLayerParserBackupParserTable(void) |
6cb00142 | 1056 | { |
429c6388 AS |
1057 | SCEnter(); |
1058 | alp_ctx_backup_unittest = alp_ctx; | |
1059 | memset(&alp_ctx, 0, sizeof(alp_ctx)); | |
1060 | SCReturn; | |
1061 | } | |
6cb00142 | 1062 | |
429c6388 AS |
1063 | void AppLayerParserRestoreParserTable(void) |
1064 | { | |
1065 | SCEnter(); | |
1066 | alp_ctx = alp_ctx_backup_unittest; | |
1067 | memset(&alp_ctx_backup_unittest, 0, sizeof(alp_ctx_backup_unittest)); | |
1068 | SCReturn; | |
6cb00142 AS |
1069 | } |
1070 | ||
1071 | /** | |
1072 | * \test Test the deallocation of app layer parser memory on occurance of | |
1073 | * error in the parsing process. | |
c1e485cc | 1074 | */ |
429c6388 | 1075 | static int AppLayerParserTest01(void) |
c1e485cc | 1076 | { |
429c6388 AS |
1077 | AppLayerParserBackupParserTable(); |
1078 | ||
9f95ab74 | 1079 | int result = 0; |
262a7300 | 1080 | Flow *f = NULL; |
c1e485cc GS |
1081 | uint8_t testbuf[] = { 0x11 }; |
1082 | uint32_t testlen = sizeof(testbuf); | |
1083 | TcpSession ssn; | |
fdefb65b | 1084 | void *alp_tctx = AppLayerParserThreadCtxAlloc(); |
c1e485cc | 1085 | |
c1e485cc | 1086 | memset(&ssn, 0, sizeof(ssn)); |
c1e485cc GS |
1087 | |
1088 | /* Register the Test protocol state and parser functions */ | |
429c6388 AS |
1089 | AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEST, STREAM_TOSERVER, |
1090 | TestProtocolParser); | |
1091 | AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_TEST, | |
1092 | TestProtocolStateAlloc, TestProtocolStateFree); | |
c1e485cc | 1093 | |
262a7300 VJ |
1094 | f = UTHBuildFlow(AF_INET, "1.2.3.4", "4.3.2.1", 20, 40); |
1095 | if (f == NULL) | |
1096 | goto end; | |
1097 | f->protoctx = &ssn; | |
262a7300 VJ |
1098 | f->alproto = ALPROTO_TEST; |
1099 | f->proto = IPPROTO_TCP; | |
c1e485cc | 1100 | |
6a53ab9c | 1101 | StreamTcpInitConfig(TRUE); |
6a53ab9c | 1102 | |
cd3e32ce | 1103 | SCMutexLock(&f->m); |
429c6388 AS |
1104 | int r = AppLayerParserParse(alp_tctx, f, ALPROTO_TEST, STREAM_TOSERVER|STREAM_EOF, |
1105 | testbuf, testlen); | |
c1e485cc | 1106 | if (r != -1) { |
9f95ab74 | 1107 | printf("returned %" PRId32 ", expected -1: ", r); |
cd3e32ce | 1108 | SCMutexUnlock(&f->m); |
c1e485cc GS |
1109 | goto end; |
1110 | } | |
cd3e32ce | 1111 | SCMutexUnlock(&f->m); |
c1e485cc | 1112 | |
429c6388 | 1113 | if (!(f->flags & FLOW_NO_APPLAYER_INSPECTION)) { |
9f95ab74 | 1114 | printf("flag should have been set, but is not: "); |
c1e485cc GS |
1115 | goto end; |
1116 | } | |
1117 | ||
9f95ab74 | 1118 | result = 1; |
429c6388 AS |
1119 | end: |
1120 | AppLayerParserRestoreParserTable(); | |
8cc525c9 | 1121 | StreamTcpFreeConfig(TRUE); |
262a7300 VJ |
1122 | |
1123 | UTHFreeFlow(f); | |
8cc525c9 PR |
1124 | return result; |
1125 | } | |
1126 | ||
6cb00142 AS |
1127 | /** |
1128 | * \test Test the deallocation of app layer parser memory on occurance of | |
1129 | * error in the parsing process for UDP. | |
8cc525c9 | 1130 | */ |
429c6388 | 1131 | static int AppLayerParserTest02(void) |
8cc525c9 | 1132 | { |
429c6388 AS |
1133 | AppLayerParserBackupParserTable(); |
1134 | ||
8cc525c9 | 1135 | int result = 1; |
262a7300 | 1136 | Flow *f = NULL; |
8cc525c9 PR |
1137 | uint8_t testbuf[] = { 0x11 }; |
1138 | uint32_t testlen = sizeof(testbuf); | |
fdefb65b | 1139 | void *alp_tctx = AppLayerParserThreadCtxAlloc(); |
8cc525c9 PR |
1140 | |
1141 | /* Register the Test protocol state and parser functions */ | |
429c6388 AS |
1142 | AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_TEST, STREAM_TOSERVER, |
1143 | TestProtocolParser); | |
1144 | AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_TEST, | |
1145 | TestProtocolStateAlloc, TestProtocolStateFree); | |
8cc525c9 | 1146 | |
262a7300 VJ |
1147 | f = UTHBuildFlow(AF_INET, "1.2.3.4", "4.3.2.1", 20, 40); |
1148 | if (f == NULL) | |
1149 | goto end; | |
1150 | f->alproto = ALPROTO_TEST; | |
1151 | f->proto = IPPROTO_UDP; | |
8cc525c9 PR |
1152 | |
1153 | StreamTcpInitConfig(TRUE); | |
8cc525c9 | 1154 | |
cd3e32ce | 1155 | SCMutexLock(&f->m); |
429c6388 | 1156 | int r = AppLayerParserParse(alp_tctx, f, ALPROTO_TEST, STREAM_TOSERVER|STREAM_EOF, testbuf, |
8cc525c9 PR |
1157 | testlen); |
1158 | if (r != -1) { | |
1159 | printf("returned %" PRId32 ", expected -1: \n", r); | |
1160 | result = 0; | |
cd3e32ce | 1161 | SCMutexUnlock(&f->m); |
8cc525c9 PR |
1162 | goto end; |
1163 | } | |
cd3e32ce | 1164 | SCMutexUnlock(&f->m); |
8cc525c9 | 1165 | |
429c6388 AS |
1166 | end: |
1167 | AppLayerParserRestoreParserTable(); | |
6a53ab9c | 1168 | StreamTcpFreeConfig(TRUE); |
262a7300 | 1169 | UTHFreeFlow(f); |
c1e485cc GS |
1170 | return result; |
1171 | } | |
1172 | ||
7c31a232 | 1173 | |
429c6388 | 1174 | void AppLayerParserRegisterUnittests(void) |
7c31a232 | 1175 | { |
429c6388 | 1176 | SCEnter(); |
9faa4b74 | 1177 | |
429c6388 | 1178 | int ip; |
f5f14880 | 1179 | AppProto alproto; |
c23742a0 | 1180 | AppLayerParserProtoCtx *ctx; |
9faa4b74 | 1181 | |
429c6388 AS |
1182 | for (ip = 0; ip < FLOW_PROTO_DEFAULT; ip++) { |
1183 | for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { | |
1184 | ctx = &alp_ctx.ctxs[ip][alproto]; | |
1185 | if (ctx->RegisterUnittests == NULL) | |
1186 | continue; | |
1187 | ctx->RegisterUnittests(); | |
9faa4b74 VJ |
1188 | } |
1189 | } | |
1190 | ||
7c31a232 AS |
1191 | UtRegisterTest("AppLayerParserTest01", AppLayerParserTest01, 1); |
1192 | UtRegisterTest("AppLayerParserTest02", AppLayerParserTest02, 1); | |
7c31a232 | 1193 | |
429c6388 | 1194 | SCReturn; |
c1e485cc | 1195 | } |
429c6388 AS |
1196 | |
1197 | #endif |