]>
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 AS |
49 | #include "app-layer-dcerpc.h" |
50 | #include "app-layer-dcerpc-udp.h" | |
c2cb155e | 51 | #include "app-layer-smb.h" |
000ce98c AS |
52 | #include "app-layer-htp.h" |
53 | #include "app-layer-ftp.h" | |
54 | #include "app-layer-ssl.h" | |
55 | #include "app-layer-ssh.h" | |
576ec7da | 56 | #include "app-layer-smtp.h" |
8e01cba8 VJ |
57 | #include "app-layer-dns-udp.h" |
58 | #include "app-layer-dns-tcp.h" | |
5a040995 | 59 | #include "app-layer-modbus.h" |
a3ffebd8 | 60 | #include "app-layer-enip.h" |
bbaa79b8 | 61 | #include "app-layer-dnp3.h" |
0d79181d VJ |
62 | #include "app-layer-nfs-tcp.h" |
63 | #include "app-layer-nfs-udp.h" | |
efe11dc3 | 64 | #include "app-layer-ntp.h" |
b9cf49e9 | 65 | #include "app-layer-tftp.h" |
c99b9462 | 66 | #include "app-layer-ikev2.h" |
77f0c11c | 67 | #include "app-layer-krb5.h" |
9210d874 | 68 | #include "app-layer-dhcp.h" |
c1b92126 | 69 | #include "app-layer-template.h" |
96dc20ab | 70 | #include "app-layer-template-rust.h" |
8e10844f | 71 | |
ddde572f | 72 | #include "conf.h" |
705471e4 | 73 | #include "util-spm.h" |
9f78d47c | 74 | |
91bc83e5 | 75 | #include "util-debug.h" |
eea5ab4a | 76 | #include "decode-events.h" |
262a7300 | 77 | #include "util-unittest-helper.h" |
5ba41c78 | 78 | #include "util-validate.h" |
91bc83e5 | 79 | |
429c6388 | 80 | #include "runmodes.h" |
cae8e06c | 81 | |
446e68ad | 82 | struct AppLayerParserThreadCtx_ { |
429c6388 | 83 | void *alproto_local_storage[FLOW_PROTO_MAX][ALPROTO_MAX]; |
446e68ad | 84 | }; |
cae8e06c | 85 | |
b74c7330 | 86 | |
429c6388 AS |
87 | /** |
88 | * \brief App layer protocol parser context. | |
89 | */ | |
c23742a0 | 90 | typedef struct AppLayerParserProtoCtx_ |
429c6388 AS |
91 | { |
92 | /* 0 - to_server, 1 - to_client. */ | |
7c8bdfd3 | 93 | AppLayerParserFPtr Parser[2]; |
66530c61 | 94 | bool logger; |
01724f04 | 95 | uint32_t logger_bits; /**< registered loggers for this proto */ |
429c6388 AS |
96 | |
97 | void *(*StateAlloc)(void); | |
98 | void (*StateFree)(void *); | |
99 | void (*StateTransactionFree)(void *, uint64_t); | |
100 | void *(*LocalStorageAlloc)(void); | |
101 | void (*LocalStorageFree)(void *); | |
102 | ||
103 | void (*Truncate)(void *, uint8_t); | |
104 | FileContainer *(*StateGetFiles)(void *, uint8_t); | |
105 | AppLayerDecoderEvents *(*StateGetEvents)(void *, uint64_t); | |
429c6388 AS |
106 | |
107 | int (*StateGetProgress)(void *alstate, uint8_t direction); | |
108 | uint64_t (*StateGetTxCnt)(void *alstate); | |
109 | void *(*StateGetTx)(void *alstate, uint64_t tx_id); | |
e96d9c11 | 110 | AppLayerGetTxIteratorFunc StateGetTxIterator; |
429c6388 AS |
111 | int (*StateGetProgressCompletionStatus)(uint8_t direction); |
112 | int (*StateGetEventInfo)(const char *event_name, | |
113 | int *event_id, AppLayerEventType *event_type); | |
114 | ||
bca0cd71 VJ |
115 | LoggerId (*StateGetTxLogged)(void *alstate, void *tx); |
116 | void (*StateSetTxLogged)(void *alstate, void *tx, LoggerId logger); | |
f3599323 | 117 | |
1cf02560 | 118 | DetectEngineState *(*GetTxDetectState)(void *tx); |
7548944b | 119 | int (*SetTxDetectState)(void *tx, DetectEngineState *); |
1cf02560 | 120 | |
daeb8fd3 VJ |
121 | uint64_t (*GetTxDetectFlags)(void *tx, uint8_t dir); |
122 | void (*SetTxDetectFlags)(void *tx, uint8_t dir, uint64_t); | |
123 | ||
b160c49e GL |
124 | /* each app-layer has its own value */ |
125 | uint32_t stream_depth; | |
126 | ||
429c6388 AS |
127 | /* Indicates the direction the parser is ready to see the data |
128 | * the first time for a flow. Values accepted - | |
129 | * STREAM_TOSERVER, STREAM_TOCLIENT */ | |
130 | uint8_t first_data_dir; | |
e1022ee5 | 131 | |
c862bbdc | 132 | /* Option flags such as supporting gaps or not. */ |
c8fb9bcb | 133 | uint32_t option_flags; |
1df38c3b | 134 | /* coccinelle: AppLayerParserProtoCtx:option_flags:APP_LAYER_PARSER_OPT_ */ |
c8fb9bcb VJ |
135 | |
136 | uint32_t internal_flags; | |
1df38c3b | 137 | /* coccinelle: AppLayerParserProtoCtx:internal_flags:APP_LAYER_PARSER_INT_ */ |
c862bbdc | 138 | |
429c6388 AS |
139 | #ifdef UNITTESTS |
140 | void (*RegisterUnittests)(void); | |
141 | #endif | |
c23742a0 | 142 | } AppLayerParserProtoCtx; |
429c6388 AS |
143 | |
144 | typedef struct AppLayerParserCtx_ { | |
c23742a0 | 145 | AppLayerParserProtoCtx ctxs[FLOW_PROTO_MAX][ALPROTO_MAX]; |
429c6388 AS |
146 | } AppLayerParserCtx; |
147 | ||
446e68ad | 148 | struct AppLayerParserState_ { |
26eb49d7 | 149 | /* coccinelle: AppLayerParserState:flags:APP_LAYER_PARSER_ */ |
429c6388 AS |
150 | uint8_t flags; |
151 | ||
152 | /* Indicates the current transaction that is being inspected. | |
153 | * We have a var per direction. */ | |
154 | uint64_t inspect_id[2]; | |
155 | /* Indicates the current transaction being logged. Unlike inspect_id, | |
156 | * we don't need a var per direction since we don't log a transaction | |
157 | * unless we have the entire transaction. */ | |
158 | uint64_t log_id; | |
429c6388 | 159 | |
5b56d324 VJ |
160 | uint64_t min_id; |
161 | ||
429c6388 AS |
162 | /* Used to store decoder events. */ |
163 | AppLayerDecoderEvents *decoder_events; | |
446e68ad | 164 | }; |
e1022ee5 | 165 | |
37203c98 VJ |
166 | #ifdef UNITTESTS |
167 | void UTHAppLayerParserStateGetIds(void *ptr, uint64_t *i1, uint64_t *i2, uint64_t *log, uint64_t *min) | |
168 | { | |
169 | struct AppLayerParserState_ *s = ptr; | |
170 | *i1 = s->inspect_id[0]; | |
171 | *i2 = s->inspect_id[1]; | |
172 | *log = s->log_id; | |
173 | *min = s->min_id; | |
174 | } | |
175 | #endif | |
176 | ||
429c6388 AS |
177 | /* Static global version of the parser context. |
178 | * Post 2.0 let's look at changing this to move it out to app-layer.c. */ | |
179 | static AppLayerParserCtx alp_ctx; | |
5a9a23f9 | 180 | |
5908dd08 GL |
181 | int AppLayerParserProtoIsRegistered(uint8_t ipproto, AppProto alproto) |
182 | { | |
183 | uint8_t ipproto_map = FlowGetProtoMapping(ipproto); | |
184 | ||
185 | return (alp_ctx.ctxs[ipproto_map][alproto].StateAlloc != NULL) ? 1 : 0; | |
186 | } | |
187 | ||
9634e60e | 188 | AppLayerParserState *AppLayerParserStateAlloc(void) |
429c6388 AS |
189 | { |
190 | SCEnter(); | |
9dc04d9f | 191 | |
cd0627cd | 192 | AppLayerParserState *pstate = (AppLayerParserState *)SCMalloc(sizeof(*pstate)); |
429c6388 AS |
193 | if (pstate == NULL) |
194 | goto end; | |
195 | memset(pstate, 0, sizeof(*pstate)); | |
9dc04d9f | 196 | |
429c6388 | 197 | end: |
9634e60e | 198 | SCReturnPtr(pstate, "AppLayerParserState"); |
9dc04d9f VJ |
199 | } |
200 | ||
9634e60e | 201 | void AppLayerParserStateFree(AppLayerParserState *pstate) |
429c6388 AS |
202 | { |
203 | SCEnter(); | |
204 | ||
9634e60e | 205 | if (pstate->decoder_events != NULL) |
347c0df9 | 206 | AppLayerDecoderEventsFreeEvents(&pstate->decoder_events); |
429c6388 | 207 | SCFree(pstate); |
9dc04d9f | 208 | |
429c6388 | 209 | SCReturn; |
9dc04d9f VJ |
210 | } |
211 | ||
429c6388 | 212 | int AppLayerParserSetup(void) |
c1e485cc | 213 | { |
429c6388 | 214 | SCEnter(); |
429c6388 | 215 | memset(&alp_ctx, 0, sizeof(alp_ctx)); |
6d562f3b VJ |
216 | SCReturnInt(0); |
217 | } | |
218 | ||
219 | void AppLayerParserPostStreamSetup(void) | |
220 | { | |
221 | AppProto alproto = 0; | |
222 | int flow_proto = 0; | |
223 | ||
b160c49e GL |
224 | /* lets set a default value for stream_depth */ |
225 | for (flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) { | |
226 | for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { | |
c8fb9bcb VJ |
227 | if (!(alp_ctx.ctxs[flow_proto][alproto].internal_flags & |
228 | APP_LAYER_PARSER_INT_STREAM_DEPTH_SET)) { | |
397f5f5f GL |
229 | alp_ctx.ctxs[flow_proto][alproto].stream_depth = |
230 | stream_config.reassembly_depth; | |
231 | } | |
b160c49e GL |
232 | } |
233 | } | |
5a9a23f9 | 234 | } |
5a9a23f9 | 235 | |
429c6388 | 236 | int AppLayerParserDeSetup(void) |
d4d18e31 | 237 | { |
429c6388 | 238 | SCEnter(); |
d4d18e31 | 239 | |
7a0dbc6f JV |
240 | SMTPParserCleanup(); |
241 | ||
429c6388 | 242 | SCReturnInt(0); |
d4d18e31 AS |
243 | } |
244 | ||
9634e60e | 245 | AppLayerParserThreadCtx *AppLayerParserThreadCtxAlloc(void) |
d4d18e31 | 246 | { |
429c6388 | 247 | SCEnter(); |
d4d18e31 | 248 | |
55255889 VJ |
249 | AppProto alproto = 0; |
250 | int flow_proto = 0; | |
72a16459 | 251 | AppLayerParserThreadCtx *tctx; |
d4d18e31 | 252 | |
429c6388 AS |
253 | tctx = SCMalloc(sizeof(*tctx)); |
254 | if (tctx == NULL) | |
255 | goto end; | |
256 | memset(tctx, 0, sizeof(*tctx)); | |
257 | ||
55255889 VJ |
258 | for (flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) { |
259 | for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { | |
260 | uint8_t ipproto = FlowGetReverseProtoMapping(flow_proto); | |
261 | ||
262 | tctx->alproto_local_storage[flow_proto][alproto] = | |
263 | AppLayerParserGetProtocolParserLocalStorage(ipproto, alproto); | |
429c6388 AS |
264 | } |
265 | } | |
266 | ||
267 | end: | |
268 | SCReturnPtr(tctx, "void *"); | |
d4d18e31 AS |
269 | } |
270 | ||
9634e60e | 271 | void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx) |
c1e485cc | 272 | { |
429c6388 | 273 | SCEnter(); |
9f78d47c | 274 | |
55255889 VJ |
275 | AppProto alproto = 0; |
276 | int flow_proto = 0; | |
277 | ||
278 | for (flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) { | |
279 | for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { | |
280 | uint8_t ipproto = FlowGetReverseProtoMapping(flow_proto); | |
429c6388 | 281 | |
55255889 VJ |
282 | AppLayerParserDestroyProtocolParserLocalStorage(ipproto, alproto, |
283 | tctx->alproto_local_storage[flow_proto][alproto]); | |
429c6388 | 284 | } |
9f78d47c | 285 | } |
cae8e06c | 286 | |
0bac43a1 | 287 | SCFree(tctx); |
429c6388 | 288 | SCReturn; |
9f78d47c VJ |
289 | } |
290 | ||
4683b0e6 VJ |
291 | /** \brief check if a parser is enabled in the config |
292 | * Returns enabled always if: were running unittests and | |
293 | * when compiled with --enable-afl | |
294 | */ | |
429c6388 AS |
295 | int AppLayerParserConfParserEnabled(const char *ipproto, |
296 | const char *alproto_name) | |
c1e485cc | 297 | { |
429c6388 AS |
298 | SCEnter(); |
299 | ||
300 | int enabled = 1; | |
301 | char param[100]; | |
302 | ConfNode *node; | |
303 | int r; | |
cae8e06c | 304 | |
4683b0e6 VJ |
305 | #ifdef AFLFUZZ_APPLAYER |
306 | goto enabled; | |
307 | #endif | |
429c6388 AS |
308 | if (RunmodeIsUnittests()) |
309 | goto enabled; | |
310 | ||
311 | r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.", | |
312 | alproto_name, ".enabled"); | |
313 | if (r < 0) { | |
314 | SCLogError(SC_ERR_FATAL, "snprintf failure."); | |
315 | exit(EXIT_FAILURE); | |
316 | } else if (r > (int)sizeof(param)) { | |
317 | SCLogError(SC_ERR_FATAL, "buffer not big enough to write param."); | |
318 | exit(EXIT_FAILURE); | |
4914d8d9 | 319 | } |
5a9a23f9 | 320 | |
429c6388 AS |
321 | node = ConfGetNode(param); |
322 | if (node == NULL) { | |
323 | SCLogDebug("Entry for %s not found.", param); | |
324 | r = snprintf(param, sizeof(param), "%s%s%s%s%s", "app-layer.protocols.", | |
325 | alproto_name, ".", ipproto, ".enabled"); | |
326 | if (r < 0) { | |
327 | SCLogError(SC_ERR_FATAL, "snprintf failure."); | |
328 | exit(EXIT_FAILURE); | |
329 | } else if (r > (int)sizeof(param)) { | |
330 | SCLogError(SC_ERR_FATAL, "buffer not big enough to write param."); | |
331 | exit(EXIT_FAILURE); | |
332 | } | |
333 | ||
334 | node = ConfGetNode(param); | |
335 | if (node == NULL) { | |
336 | SCLogDebug("Entry for %s not found.", param); | |
337 | goto enabled; | |
338 | } | |
9f78d47c | 339 | } |
9f78d47c | 340 | |
16e4c92b | 341 | if (ConfValIsTrue(node->val)) { |
429c6388 | 342 | goto enabled; |
16e4c92b | 343 | } else if (ConfValIsFalse(node->val)) { |
429c6388 AS |
344 | goto disabled; |
345 | } else if (strcasecmp(node->val, "detection-only") == 0) { | |
ff8dae3b | 346 | goto disabled; |
9f78d47c | 347 | } else { |
429c6388 AS |
348 | SCLogError(SC_ERR_FATAL, "Invalid value found for %s.", param); |
349 | exit(EXIT_FAILURE); | |
9f78d47c | 350 | } |
429c6388 AS |
351 | |
352 | disabled: | |
353 | enabled = 0; | |
354 | enabled: | |
355 | SCReturnInt(enabled); | |
9f78d47c VJ |
356 | } |
357 | ||
429c6388 AS |
358 | /***** Parser related registration *****/ |
359 | ||
5cdeadb3 | 360 | int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, |
429c6388 | 361 | uint8_t direction, |
7c8bdfd3 | 362 | AppLayerParserFPtr Parser) |
c1e485cc | 363 | { |
574bcea0 VJ |
364 | SCEnter(); |
365 | ||
429c6388 AS |
366 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
367 | Parser[(direction & STREAM_TOSERVER) ? 0 : 1] = Parser; | |
9f78d47c | 368 | |
574bcea0 | 369 | SCReturnInt(0); |
9f78d47c VJ |
370 | } |
371 | ||
5cdeadb3 | 372 | void AppLayerParserRegisterParserAcceptableDataDirection(uint8_t ipproto, AppProto alproto, |
429c6388 | 373 | uint8_t direction) |
c13ad8c2 | 374 | { |
429c6388 AS |
375 | SCEnter(); |
376 | ||
377 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].first_data_dir |= | |
378 | (direction & (STREAM_TOSERVER | STREAM_TOCLIENT)); | |
379 | ||
380 | SCReturn; | |
c13ad8c2 AS |
381 | } |
382 | ||
c862bbdc | 383 | void AppLayerParserRegisterOptionFlags(uint8_t ipproto, AppProto alproto, |
c8fb9bcb | 384 | uint32_t flags) |
c862bbdc JI |
385 | { |
386 | SCEnter(); | |
387 | ||
c8fb9bcb | 388 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].option_flags |= flags; |
c862bbdc JI |
389 | |
390 | SCReturn; | |
391 | } | |
392 | ||
5cdeadb3 | 393 | void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
394 | void *(*StateAlloc)(void), |
395 | void (*StateFree)(void *)) | |
c1e485cc | 396 | { |
574bcea0 VJ |
397 | SCEnter(); |
398 | ||
429c6388 AS |
399 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateAlloc = |
400 | StateAlloc; | |
401 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateFree = | |
402 | StateFree; | |
086ba5f4 | 403 | |
429c6388 AS |
404 | SCReturn; |
405 | } | |
086ba5f4 | 406 | |
5cdeadb3 | 407 | void AppLayerParserRegisterLocalStorageFunc(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
408 | void *(*LocalStorageAlloc)(void), |
409 | void (*LocalStorageFree)(void *)) | |
410 | { | |
411 | SCEnter(); | |
574bcea0 | 412 | |
429c6388 AS |
413 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].LocalStorageAlloc = |
414 | LocalStorageAlloc; | |
415 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].LocalStorageFree = | |
416 | LocalStorageFree; | |
086ba5f4 | 417 | |
429c6388 AS |
418 | SCReturn; |
419 | } | |
086ba5f4 | 420 | |
5cdeadb3 | 421 | void AppLayerParserRegisterGetFilesFunc(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
422 | FileContainer *(*StateGetFiles)(void *, uint8_t)) |
423 | { | |
424 | SCEnter(); | |
086ba5f4 | 425 | |
429c6388 AS |
426 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetFiles = |
427 | StateGetFiles; | |
086ba5f4 | 428 | |
429c6388 AS |
429 | SCReturn; |
430 | } | |
086ba5f4 | 431 | |
5cdeadb3 | 432 | void AppLayerParserRegisterGetEventsFunc(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
433 | AppLayerDecoderEvents *(*StateGetEvents)(void *, uint64_t)) |
434 | { | |
435 | SCEnter(); | |
574bcea0 | 436 | |
429c6388 AS |
437 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetEvents = |
438 | StateGetEvents; | |
086ba5f4 | 439 | |
429c6388 | 440 | SCReturn; |
086ba5f4 VJ |
441 | } |
442 | ||
f3599323 | 443 | void AppLayerParserRegisterLoggerFuncs(uint8_t ipproto, AppProto alproto, |
bca0cd71 VJ |
444 | LoggerId (*StateGetTxLogged)(void *, void *), |
445 | void (*StateSetTxLogged)(void *, void *, LoggerId)) | |
f3599323 MK |
446 | { |
447 | SCEnter(); | |
448 | ||
449 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetTxLogged = | |
450 | StateGetTxLogged; | |
451 | ||
452 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateSetTxLogged = | |
453 | StateSetTxLogged; | |
454 | ||
455 | SCReturn; | |
456 | } | |
457 | ||
01724f04 VJ |
458 | void AppLayerParserRegisterLoggerBits(uint8_t ipproto, AppProto alproto, LoggerId bits) |
459 | { | |
460 | SCEnter(); | |
461 | ||
462 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].logger_bits = bits; | |
463 | ||
464 | SCReturn; | |
465 | } | |
466 | ||
5cdeadb3 | 467 | void AppLayerParserRegisterLogger(uint8_t ipproto, AppProto alproto) |
429c6388 AS |
468 | { |
469 | SCEnter(); | |
9f78d47c | 470 | |
66530c61 | 471 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].logger = true; |
9f78d47c | 472 | |
429c6388 AS |
473 | SCReturn; |
474 | } | |
9f78d47c | 475 | |
5cdeadb3 | 476 | void AppLayerParserRegisterTruncateFunc(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
477 | void (*Truncate)(void *, uint8_t)) |
478 | { | |
479 | SCEnter(); | |
574bcea0 | 480 | |
429c6388 | 481 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].Truncate = Truncate; |
574bcea0 | 482 | |
429c6388 AS |
483 | SCReturn; |
484 | } | |
9f78d47c | 485 | |
5cdeadb3 | 486 | void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
487 | int (*StateGetProgress)(void *alstate, uint8_t direction)) |
488 | { | |
489 | SCEnter(); | |
9f78d47c | 490 | |
429c6388 AS |
491 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
492 | StateGetProgress = StateGetProgress; | |
9f78d47c | 493 | |
429c6388 | 494 | SCReturn; |
9f78d47c VJ |
495 | } |
496 | ||
5cdeadb3 | 497 | void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, |
429c6388 | 498 | void (*StateTransactionFree)(void *, uint64_t)) |
c1e485cc | 499 | { |
574bcea0 | 500 | SCEnter(); |
9f78d47c | 501 | |
429c6388 AS |
502 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
503 | StateTransactionFree = StateTransactionFree; | |
9f78d47c | 504 | |
429c6388 AS |
505 | SCReturn; |
506 | } | |
9f78d47c | 507 | |
5cdeadb3 | 508 | void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
509 | uint64_t (*StateGetTxCnt)(void *alstate)) |
510 | { | |
511 | SCEnter(); | |
9f78d47c | 512 | |
429c6388 AS |
513 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
514 | StateGetTxCnt = StateGetTxCnt; | |
9f78d47c | 515 | |
429c6388 AS |
516 | SCReturn; |
517 | } | |
9f78d47c | 518 | |
5cdeadb3 | 519 | void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
520 | void *(StateGetTx)(void *alstate, uint64_t tx_id)) |
521 | { | |
522 | SCEnter(); | |
9f78d47c | 523 | |
429c6388 AS |
524 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
525 | StateGetTx = StateGetTx; | |
9f78d47c | 526 | |
429c6388 | 527 | SCReturn; |
9f78d47c VJ |
528 | } |
529 | ||
e96d9c11 VJ |
530 | void AppLayerParserRegisterGetTxIterator(uint8_t ipproto, AppProto alproto, |
531 | AppLayerGetTxIteratorFunc Func) | |
532 | { | |
533 | SCEnter(); | |
534 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetTxIterator = Func; | |
535 | SCReturn; | |
536 | } | |
537 | ||
c4b918b6 | 538 | void AppLayerParserRegisterGetStateProgressCompletionStatus(AppProto alproto, |
429c6388 | 539 | int (*StateGetProgressCompletionStatus)(uint8_t direction)) |
c1e485cc | 540 | { |
429c6388 | 541 | SCEnter(); |
f1f7df07 | 542 | |
c4b918b6 | 543 | alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto]. |
429c6388 | 544 | StateGetProgressCompletionStatus = StateGetProgressCompletionStatus; |
f1f7df07 | 545 | |
429c6388 AS |
546 | SCReturn; |
547 | } | |
f1f7df07 | 548 | |
5cdeadb3 | 549 | void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, |
429c6388 AS |
550 | int (*StateGetEventInfo)(const char *event_name, int *event_id, |
551 | AppLayerEventType *event_type)) | |
552 | { | |
553 | SCEnter(); | |
f1f7df07 | 554 | |
429c6388 AS |
555 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
556 | StateGetEventInfo = StateGetEventInfo; | |
d9686fae | 557 | |
429c6388 AS |
558 | SCReturn; |
559 | } | |
d9686fae | 560 | |
1cf02560 VJ |
561 | void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, |
562 | DetectEngineState *(*GetTxDetectState)(void *tx), | |
7548944b | 563 | int (*SetTxDetectState)(void *tx, DetectEngineState *)) |
1cf02560 VJ |
564 | { |
565 | SCEnter(); | |
566 | ||
567 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState = GetTxDetectState; | |
568 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectState = SetTxDetectState; | |
569 | ||
570 | SCReturn; | |
571 | } | |
572 | ||
daeb8fd3 VJ |
573 | void AppLayerParserRegisterDetectFlagsFuncs(uint8_t ipproto, AppProto alproto, |
574 | uint64_t(*GetTxDetectFlags)(void *tx, uint8_t dir), | |
575 | void (*SetTxDetectFlags)(void *tx, uint8_t dir, uint64_t)) | |
576 | { | |
577 | SCEnter(); | |
578 | ||
579 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectFlags = GetTxDetectFlags; | |
580 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectFlags = SetTxDetectFlags; | |
581 | ||
582 | SCReturn; | |
583 | } | |
584 | ||
a0fad6bb VJ |
585 | void AppLayerParserRegisterMpmIDsFuncs(uint8_t ipproto, AppProto alproto, |
586 | uint64_t(*GetTxMpmIDs)(void *tx), | |
587 | int (*SetTxMpmIDs)(void *tx, uint64_t)) | |
588 | { | |
589 | SCEnter(); | |
5f890296 VJ |
590 | SCLogWarning(SC_WARN_DEPRECATED, "%u/%s: GetTxMpmIDs/SetTxMpmIDs is no longer used", |
591 | ipproto, AppProtoToString(alproto)); | |
a0fad6bb VJ |
592 | SCReturn; |
593 | } | |
594 | ||
429c6388 | 595 | /***** Get and transaction functions *****/ |
d9686fae | 596 | |
5cdeadb3 | 597 | void *AppLayerParserGetProtocolParserLocalStorage(uint8_t ipproto, AppProto alproto) |
429c6388 AS |
598 | { |
599 | SCEnter(); | |
dc1599e0 | 600 | void * r = NULL; |
429c6388 AS |
601 | |
602 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
603 | LocalStorageAlloc != NULL) | |
604 | { | |
dc1599e0 | 605 | r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
606 | LocalStorageAlloc(); | |
d9686fae AS |
607 | } |
608 | ||
dc1599e0 | 609 | SCReturnPtr(r, "void *"); |
f1f7df07 VJ |
610 | } |
611 | ||
5cdeadb3 | 612 | void AppLayerParserDestroyProtocolParserLocalStorage(uint8_t ipproto, AppProto alproto, |
429c6388 | 613 | void *local_data) |
68425453 | 614 | { |
429c6388 | 615 | SCEnter(); |
68425453 | 616 | |
429c6388 AS |
617 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
618 | LocalStorageFree != NULL) | |
619 | { | |
620 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
621 | LocalStorageFree(local_data); | |
68425453 EL |
622 | } |
623 | ||
429c6388 | 624 | SCReturn; |
68425453 EL |
625 | } |
626 | ||
e96d9c11 VJ |
627 | /** \brief default tx iterator |
628 | * | |
629 | * Used if the app layer parser doesn't register its own iterator. | |
630 | * Simply walks the tx_id space until it finds a tx. Uses 'state' to | |
631 | * keep track of where it left off. | |
632 | * | |
633 | * \retval txptr or NULL if no more txs in list | |
634 | */ | |
635 | static AppLayerGetTxIterTuple AppLayerDefaultGetTxIterator( | |
636 | const uint8_t ipproto, const AppProto alproto, | |
637 | void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, | |
638 | AppLayerGetTxIterState *state) | |
639 | { | |
640 | uint64_t ustate = *(uint64_t *)state; | |
641 | uint64_t tx_id = MAX(min_tx_id, ustate); | |
642 | for ( ; tx_id < max_tx_id; tx_id++) { | |
643 | void *tx_ptr = AppLayerParserGetTx(ipproto, alproto, alstate, tx_id); | |
644 | if (tx_ptr != NULL) { | |
645 | ustate = tx_id + 1; | |
646 | *state = *(AppLayerGetTxIterState *)&ustate; | |
647 | AppLayerGetTxIterTuple tuple = { | |
648 | .tx_ptr = tx_ptr, | |
649 | .tx_id = tx_id, | |
650 | .has_next = (tx_id + 1 < max_tx_id), | |
651 | }; | |
652 | SCLogDebug("tulpe: %p/%"PRIu64"/%s", tuple.tx_ptr, tuple.tx_id, | |
653 | tuple.has_next ? "true" : "false"); | |
654 | return tuple; | |
655 | } | |
656 | } | |
657 | ||
658 | AppLayerGetTxIterTuple no_tuple = { NULL, 0, false }; | |
659 | return no_tuple; | |
660 | } | |
661 | ||
662 | AppLayerGetTxIteratorFunc AppLayerGetTxIterator(const uint8_t ipproto, | |
663 | const AppProto alproto) | |
664 | { | |
665 | AppLayerGetTxIteratorFunc Func = | |
666 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetTxIterator; | |
667 | return Func ? Func : AppLayerDefaultGetTxIterator; | |
668 | } | |
669 | ||
f3599323 | 670 | void AppLayerParserSetTxLogged(uint8_t ipproto, AppProto alproto, |
bca0cd71 | 671 | void *alstate, void *tx, LoggerId logger) |
f3599323 MK |
672 | { |
673 | SCEnter(); | |
674 | ||
675 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
676 | StateSetTxLogged != NULL) { | |
677 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
678 | StateSetTxLogged(alstate, tx, logger); | |
679 | } | |
680 | ||
681 | SCReturn; | |
682 | } | |
683 | ||
bca0cd71 VJ |
684 | LoggerId AppLayerParserGetTxLogged(const Flow *f, |
685 | void *alstate, void *tx) | |
f3599323 MK |
686 | { |
687 | SCEnter(); | |
688 | ||
bca0cd71 | 689 | LoggerId r = 0; |
4459b887 VJ |
690 | if (alp_ctx.ctxs[f->protomap][f->alproto].StateGetTxLogged != NULL) { |
691 | r = alp_ctx.ctxs[f->protomap][f->alproto]. | |
bca0cd71 | 692 | StateGetTxLogged(alstate, tx); |
f3599323 MK |
693 | } |
694 | ||
bca0cd71 | 695 | SCReturnUInt(r); |
f3599323 MK |
696 | } |
697 | ||
9634e60e | 698 | uint64_t AppLayerParserGetTransactionLogId(AppLayerParserState *pstate) |
c1e485cc | 699 | { |
429c6388 | 700 | SCEnter(); |
8e10844f | 701 | |
0564a8da | 702 | SCReturnCT((pstate == NULL) ? 0 : pstate->log_id, "uint64_t"); |
429c6388 | 703 | } |
8e10844f | 704 | |
e9fccfa6 | 705 | void AppLayerParserSetTransactionLogId(AppLayerParserState *pstate, uint64_t tx_id) |
429c6388 AS |
706 | { |
707 | SCEnter(); | |
5fc30051 | 708 | |
0564a8da | 709 | if (pstate != NULL) |
e9fccfa6 | 710 | pstate->log_id = tx_id; |
5a9a23f9 | 711 | |
429c6388 | 712 | SCReturn; |
8e10844f VJ |
713 | } |
714 | ||
9634e60e | 715 | uint64_t AppLayerParserGetTransactionInspectId(AppLayerParserState *pstate, uint8_t direction) |
c1e485cc | 716 | { |
429c6388 | 717 | SCEnter(); |
8e10844f | 718 | |
0564a8da VJ |
719 | if (pstate == NULL) |
720 | SCReturnCT(0ULL, "uint64_t"); | |
721 | ||
9634e60e | 722 | SCReturnCT(pstate->inspect_id[direction & STREAM_TOSERVER ? 0 : 1], "uint64_t"); |
429c6388 | 723 | } |
5fc30051 | 724 | |
5c01b409 | 725 | void AppLayerParserSetTransactionInspectId(const Flow *f, AppLayerParserState *pstate, |
af51e0f5 VJ |
726 | void *alstate, const uint8_t flags, |
727 | bool tag_txs_as_inspected) | |
429c6388 AS |
728 | { |
729 | SCEnter(); | |
59780ca7 | 730 | |
3fc87595 | 731 | const int direction = (flags & STREAM_TOSERVER) ? 0 : 1; |
5c01b409 | 732 | const uint64_t total_txs = AppLayerParserGetTxCnt(f, alstate); |
6946e0be | 733 | uint64_t idx = AppLayerParserGetTransactionInspectId(pstate, flags); |
5c01b409 | 734 | const int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(f->alproto, flags); |
af51e0f5 VJ |
735 | const uint8_t ipproto = f->proto; |
736 | const AppProto alproto = f->alproto; | |
8e10844f | 737 | |
e96d9c11 VJ |
738 | AppLayerGetTxIteratorFunc IterFunc = AppLayerGetTxIterator(ipproto, alproto); |
739 | AppLayerGetTxIterState state; | |
740 | memset(&state, 0, sizeof(state)); | |
741 | ||
7a96d18f VJ |
742 | SCLogDebug("called: %s, tag_txs_as_inspected %s",direction==0?"toserver":"toclient", |
743 | tag_txs_as_inspected?"true":"false"); | |
744 | ||
745 | /* mark all txs as inspected if the applayer progress is | |
746 | * at the 'end state'. */ | |
e96d9c11 VJ |
747 | while (1) { |
748 | AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, idx, total_txs, &state); | |
749 | if (ires.tx_ptr == NULL) | |
750 | break; | |
751 | ||
752 | void *tx = ires.tx_ptr; | |
753 | idx = ires.tx_id; | |
754 | ||
af51e0f5 | 755 | int state_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx, flags); |
e96d9c11 VJ |
756 | if (state_progress < state_done_progress) |
757 | break; | |
758 | ||
759 | if (tag_txs_as_inspected) { | |
760 | uint64_t detect_flags = AppLayerParserGetTxDetectFlags(ipproto, alproto, tx, flags); | |
761 | if ((detect_flags & APP_LAYER_TX_INSPECTED_FLAG) == 0) { | |
762 | detect_flags |= APP_LAYER_TX_INSPECTED_FLAG; | |
763 | AppLayerParserSetTxDetectFlags(ipproto, alproto, tx, flags, detect_flags); | |
764 | SCLogDebug("%p/%"PRIu64" in-order tx is done for direction %s. Flag %016"PRIx64, | |
765 | tx, idx, flags & STREAM_TOSERVER ? "toserver" : "toclient", detect_flags); | |
af51e0f5 | 766 | } |
e96d9c11 VJ |
767 | } |
768 | if (!ires.has_next) | |
429c6388 | 769 | break; |
0e402311 | 770 | idx++; |
8e10844f | 771 | } |
6946e0be | 772 | pstate->inspect_id[direction] = idx; |
7a96d18f | 773 | SCLogDebug("inspect_id now %"PRIu64, pstate->inspect_id[direction]); |
8e10844f | 774 | |
7a96d18f VJ |
775 | /* if necessary we flag all txs that are complete as 'inspected' |
776 | * also move inspect_id forward. */ | |
af51e0f5 | 777 | if (tag_txs_as_inspected) { |
e96d9c11 VJ |
778 | /* continue at idx */ |
779 | while (1) { | |
780 | AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, idx, total_txs, &state); | |
781 | if (ires.tx_ptr == NULL) | |
782 | break; | |
783 | ||
784 | void *tx = ires.tx_ptr; | |
785 | /* if we got a higher id than the minimum we requested, we | |
786 | * skipped a bunch of 'null-txs'. Lets see if we can up the | |
787 | * inspect tracker */ | |
788 | if (ires.tx_id > idx && pstate->inspect_id[direction] == idx) { | |
789 | pstate->inspect_id[direction] = ires.tx_id; | |
af51e0f5 | 790 | } |
e96d9c11 VJ |
791 | idx = ires.tx_id; |
792 | ||
793 | const int state_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx, flags); | |
794 | if (state_progress < state_done_progress) | |
795 | break; | |
796 | ||
797 | uint64_t detect_flags = AppLayerParserGetTxDetectFlags(ipproto, alproto, tx, flags); | |
798 | if ((detect_flags & APP_LAYER_TX_INSPECTED_FLAG) == 0) { | |
799 | detect_flags |= APP_LAYER_TX_INSPECTED_FLAG; | |
800 | AppLayerParserSetTxDetectFlags(ipproto, alproto, tx, flags, detect_flags); | |
801 | SCLogDebug("%p/%"PRIu64" out of order tx is done for direction %s. Flag %016"PRIx64, | |
802 | tx, idx, flags & STREAM_TOSERVER ? "toserver" : "toclient", detect_flags); | |
803 | ||
804 | SCLogDebug("%p/%"PRIu64" out of order tx. Update inspect_id? %"PRIu64, | |
805 | tx, idx, pstate->inspect_id[direction]); | |
7a96d18f VJ |
806 | if (pstate->inspect_id[direction]+1 == idx) |
807 | pstate->inspect_id[direction] = idx; | |
808 | } | |
e96d9c11 VJ |
809 | if (!ires.has_next) |
810 | break; | |
0e402311 | 811 | idx++; |
af51e0f5 VJ |
812 | } |
813 | } | |
814 | ||
429c6388 | 815 | SCReturn; |
9faa4b74 | 816 | } |
9faa4b74 | 817 | |
9634e60e | 818 | AppLayerDecoderEvents *AppLayerParserGetDecoderEvents(AppLayerParserState *pstate) |
c1e485cc | 819 | { |
429c6388 | 820 | SCEnter(); |
9f78d47c | 821 | |
9634e60e | 822 | SCReturnPtr(pstate->decoder_events, |
429c6388 | 823 | "AppLayerDecoderEvents *"); |
70b32f73 VJ |
824 | } |
825 | ||
9634e60e | 826 | void AppLayerParserSetDecoderEvents(AppLayerParserState *pstate, AppLayerDecoderEvents *devents) |
9a6aef45 | 827 | { |
9634e60e | 828 | pstate->decoder_events = devents; |
9a6aef45 AS |
829 | } |
830 | ||
5cdeadb3 | 831 | AppLayerDecoderEvents *AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, |
429c6388 | 832 | void *alstate, uint64_t tx_id) |
869109a6 | 833 | { |
429c6388 | 834 | SCEnter(); |
869109a6 | 835 | |
429c6388 | 836 | AppLayerDecoderEvents *ptr = NULL; |
869109a6 | 837 | |
429c6388 AS |
838 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
839 | StateGetEvents != NULL) | |
840 | { | |
841 | ptr = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
842 | StateGetEvents(alstate, tx_id); | |
01a35bb6 AS |
843 | } |
844 | ||
429c6388 | 845 | SCReturnPtr(ptr, "AppLayerDecoderEvents *"); |
6cb00142 | 846 | } |
70b32f73 | 847 | |
5cdeadb3 | 848 | FileContainer *AppLayerParserGetFiles(uint8_t ipproto, AppProto alproto, |
429c6388 | 849 | void *alstate, uint8_t direction) |
c1e485cc | 850 | { |
91bc83e5 | 851 | SCEnter(); |
8e10844f | 852 | |
429c6388 | 853 | FileContainer *ptr = NULL; |
45d86ff5 | 854 | |
429c6388 AS |
855 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. |
856 | StateGetFiles != NULL) | |
857 | { | |
858 | ptr = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
859 | StateGetFiles(alstate, direction); | |
3b3dce83 | 860 | } |
5ba41c78 | 861 | |
429c6388 | 862 | SCReturnPtr(ptr, "FileContainer *"); |
70b32f73 | 863 | } |
70b32f73 | 864 | |
c06c595c VJ |
865 | /** |
866 | * \brief remove obsolete (inspected and logged) transactions | |
867 | */ | |
7a96d18f | 868 | void AppLayerParserTransactionsCleanup(Flow *f) |
c06c595c | 869 | { |
e62e4bdc | 870 | SCEnter(); |
c06c595c VJ |
871 | DEBUG_ASSERT_FLOW_LOCKED(f); |
872 | ||
3fc87595 VJ |
873 | AppLayerParserProtoCtx *p = &alp_ctx.ctxs[f->protomap][f->alproto]; |
874 | if (unlikely(p->StateTransactionFree == NULL)) | |
e62e4bdc | 875 | SCReturn; |
c06c595c | 876 | |
7a96d18f VJ |
877 | const uint8_t ipproto = f->proto; |
878 | const AppProto alproto = f->alproto; | |
879 | void * const alstate = f->alstate; | |
880 | AppLayerParserState * const alparser = f->alparser; | |
881 | ||
882 | if (alstate == NULL || alparser == NULL) | |
e62e4bdc | 883 | SCReturn; |
7a96d18f VJ |
884 | |
885 | const uint64_t min = alparser->min_id; | |
886 | const uint64_t total_txs = AppLayerParserGetTxCnt(f, alstate); | |
887 | const LoggerId logger_expectation = AppLayerParserProtocolGetLoggerBits(ipproto, alproto); | |
888 | const int tx_end_state_ts = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOSERVER); | |
889 | const int tx_end_state_tc = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOCLIENT); | |
890 | ||
e96d9c11 VJ |
891 | AppLayerGetTxIteratorFunc IterFunc = AppLayerGetTxIterator(ipproto, alproto); |
892 | AppLayerGetTxIterState state; | |
893 | memset(&state, 0, sizeof(state)); | |
894 | uint64_t i = min; | |
895 | uint64_t new_min = min; | |
e62e4bdc | 896 | SCLogDebug("start min %"PRIu64, min); |
d34e4106 | 897 | bool skipped = false; |
e96d9c11 VJ |
898 | |
899 | while (1) { | |
900 | AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, i, total_txs, &state); | |
901 | if (ires.tx_ptr == NULL) | |
902 | break; | |
903 | ||
904 | void *tx = ires.tx_ptr; | |
0e402311 | 905 | i = ires.tx_id; // actual tx id for the tx the IterFunc returned |
e96d9c11 | 906 | |
7a96d18f | 907 | SCLogDebug("%p/%"PRIu64" checking", tx, i); |
5b56d324 | 908 | |
7a96d18f VJ |
909 | const int tx_progress_tc = AppLayerParserGetStateProgress(ipproto, alproto, tx, STREAM_TOCLIENT); |
910 | if (tx_progress_tc < tx_end_state_tc) { | |
911 | SCLogDebug("%p/%"PRIu64" skipping: tc parser not done", tx, i); | |
d34e4106 | 912 | skipped = true; |
e96d9c11 | 913 | goto next; |
7a96d18f VJ |
914 | } |
915 | const int tx_progress_ts = AppLayerParserGetStateProgress(ipproto, alproto, tx, STREAM_TOSERVER); | |
916 | if (tx_progress_ts < tx_end_state_ts) { | |
917 | SCLogDebug("%p/%"PRIu64" skipping: ts parser not done", tx, i); | |
d34e4106 | 918 | skipped = true; |
e96d9c11 | 919 | goto next; |
7a96d18f VJ |
920 | } |
921 | if (f->sgh_toserver != NULL) { | |
922 | uint64_t detect_flags_ts = AppLayerParserGetTxDetectFlags(ipproto, alproto, tx, STREAM_TOSERVER); | |
923 | if (!(detect_flags_ts & APP_LAYER_TX_INSPECTED_FLAG)) { | |
924 | SCLogDebug("%p/%"PRIu64" skipping: TS inspect not done: ts:%"PRIx64, | |
925 | tx, i, detect_flags_ts); | |
d34e4106 | 926 | skipped = true; |
e96d9c11 | 927 | goto next; |
7a96d18f VJ |
928 | } |
929 | } | |
930 | if (f->sgh_toclient != NULL) { | |
931 | uint64_t detect_flags_tc = AppLayerParserGetTxDetectFlags(ipproto, alproto, tx, STREAM_TOCLIENT); | |
932 | if (!(detect_flags_tc & APP_LAYER_TX_INSPECTED_FLAG)) { | |
933 | SCLogDebug("%p/%"PRIu64" skipping: TC inspect not done: tc:%"PRIx64, | |
934 | tx, i, detect_flags_tc); | |
d34e4106 | 935 | skipped = true; |
e96d9c11 | 936 | goto next; |
7a96d18f VJ |
937 | } |
938 | } | |
939 | if (logger_expectation != 0) { | |
940 | LoggerId tx_logged = AppLayerParserGetTxLogged(f, alstate, tx); | |
941 | if (tx_logged != logger_expectation) { | |
942 | SCLogDebug("%p/%"PRIu64" skipping: logging not done: want:%"PRIx32", have:%"PRIx32, | |
943 | tx, i, logger_expectation, tx_logged); | |
d34e4106 | 944 | skipped = true; |
e96d9c11 | 945 | goto next; |
7a96d18f VJ |
946 | } |
947 | } | |
5b56d324 | 948 | |
7a96d18f VJ |
949 | /* if we are here, the tx can be freed. */ |
950 | p->StateTransactionFree(alstate, i); | |
951 | SCLogDebug("%p/%"PRIu64" freed", tx, i); | |
e96d9c11 | 952 | |
d34e4106 | 953 | /* if we didn't skip any tx so far, up the minimum */ |
0e402311 | 954 | SCLogDebug("skipped? %s i %"PRIu64", new_min %"PRIu64, skipped ? "true" : "false", i, new_min); |
d34e4106 | 955 | if (!skipped) |
e96d9c11 | 956 | new_min = i + 1; |
0e402311 | 957 | SCLogDebug("final i %"PRIu64", new_min %"PRIu64, i, new_min); |
e96d9c11 VJ |
958 | |
959 | next: | |
0e402311 VJ |
960 | if (!ires.has_next) { |
961 | /* this was the last tx. See if we skipped any. If not | |
962 | * we removed all and can update the minimum to the max | |
963 | * id. */ | |
964 | SCLogDebug("no next: cur tx i %"PRIu64", total %"PRIu64, i, total_txs); | |
965 | if (!skipped) { | |
966 | new_min = total_txs; | |
967 | SCLogDebug("no next: cur tx i %"PRIu64", total %"PRIu64": " | |
968 | "new_min updated to %"PRIu64, i, total_txs, new_min); | |
969 | } | |
e96d9c11 | 970 | break; |
0e402311 VJ |
971 | } |
972 | i++; | |
e96d9c11 VJ |
973 | } |
974 | ||
975 | /* see if we need to bring all trackers up to date. */ | |
e62e4bdc | 976 | SCLogDebug("update f->alparser->min_id? %"PRIu64" vs %"PRIu64, new_min, alparser->min_id); |
e96d9c11 VJ |
977 | if (new_min > alparser->min_id) { |
978 | const uint64_t next_id = new_min; | |
979 | alparser->min_id = next_id; | |
980 | alparser->inspect_id[0] = MAX(alparser->inspect_id[0], next_id); | |
981 | alparser->inspect_id[1] = MAX(alparser->inspect_id[1], next_id); | |
982 | alparser->log_id = MAX(alparser->log_id, next_id); | |
983 | SCLogDebug("updated f->alparser->min_id %"PRIu64, alparser->min_id); | |
c06c595c | 984 | } |
e62e4bdc | 985 | SCReturn; |
c06c595c VJ |
986 | } |
987 | ||
ea571add VJ |
988 | #define IS_DISRUPTED(flags) \ |
989 | ((flags) & (STREAM_DEPTH|STREAM_GAP)) | |
990 | ||
991 | /** | |
992 | * \brief get the progress value for a tx/protocol | |
993 | * | |
994 | * If the stream is disrupted, we return the 'completion' value. | |
995 | */ | |
5cdeadb3 | 996 | int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, |
ea571add | 997 | void *alstate, uint8_t flags) |
d4d18e31 | 998 | { |
73efb4c7 | 999 | SCEnter(); |
dc1599e0 | 1000 | int r = 0; |
ea571add | 1001 | if (unlikely(IS_DISRUPTED(flags))) { |
c4b918b6 | 1002 | r = alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto]. |
ea571add VJ |
1003 | StateGetProgressCompletionStatus(flags); |
1004 | } else { | |
1005 | r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
1006 | StateGetProgress(alstate, flags); | |
1007 | } | |
dc1599e0 | 1008 | SCReturnInt(r); |
d4d18e31 | 1009 | } |
70b32f73 | 1010 | |
5c01b409 | 1011 | uint64_t AppLayerParserGetTxCnt(const Flow *f, void *alstate) |
d4d18e31 | 1012 | { |
16cfae2f | 1013 | SCEnter(); |
dc1599e0 | 1014 | uint64_t r = 0; |
5c01b409 | 1015 | r = alp_ctx.ctxs[f->protomap][f->alproto]. |
dc1599e0 | 1016 | StateGetTxCnt(alstate); |
1017 | SCReturnCT(r, "uint64_t"); | |
16cfae2f VJ |
1018 | } |
1019 | ||
5cdeadb3 | 1020 | void *AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id) |
ddde572f | 1021 | { |
429c6388 | 1022 | SCEnter(); |
dc1599e0 | 1023 | void * r = NULL; |
1024 | r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
1025 | StateGetTx(alstate, tx_id); | |
1026 | SCReturnPtr(r, "void *"); | |
ddde572f AS |
1027 | } |
1028 | ||
c4b918b6 MK |
1029 | int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto, |
1030 | uint8_t direction) | |
6cb00142 | 1031 | { |
429c6388 | 1032 | SCEnter(); |
dc1599e0 | 1033 | int r = 0; |
c4b918b6 | 1034 | r = alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto]. |
dc1599e0 | 1035 | StateGetProgressCompletionStatus(direction); |
1036 | SCReturnInt(r); | |
6cb00142 AS |
1037 | } |
1038 | ||
5cdeadb3 | 1039 | int AppLayerParserGetEventInfo(uint8_t ipproto, AppProto alproto, const char *event_name, |
429c6388 | 1040 | int *event_id, AppLayerEventType *event_type) |
6f8cfd99 | 1041 | { |
429c6388 AS |
1042 | SCEnter(); |
1043 | int ipproto_map = FlowGetProtoMapping(ipproto); | |
1cbd1cdf VJ |
1044 | int r = (alp_ctx.ctxs[ipproto_map][alproto].StateGetEventInfo == NULL) ? |
1045 | -1 : alp_ctx.ctxs[ipproto_map][alproto].StateGetEventInfo(event_name, event_id, event_type); | |
1046 | SCReturnInt(r); | |
6f8cfd99 AS |
1047 | } |
1048 | ||
f5f14880 | 1049 | uint8_t AppLayerParserGetFirstDataDir(uint8_t ipproto, AppProto alproto) |
432c3317 | 1050 | { |
429c6388 | 1051 | SCEnter(); |
dc1599e0 | 1052 | uint8_t r = 0; |
1053 | r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
1054 | first_data_dir; | |
1055 | SCReturnCT(r, "uint8_t"); | |
432c3317 | 1056 | } |
7c31a232 | 1057 | |
3148ff34 VJ |
1058 | uint64_t AppLayerParserGetTransactionActive(const Flow *f, |
1059 | AppLayerParserState *pstate, uint8_t direction) | |
d9686fae | 1060 | { |
429c6388 | 1061 | SCEnter(); |
d9686fae | 1062 | |
429c6388 | 1063 | uint64_t active_id; |
d9686fae | 1064 | |
9634e60e VJ |
1065 | uint64_t log_id = pstate->log_id; |
1066 | uint64_t inspect_id = pstate->inspect_id[direction & STREAM_TOSERVER ? 0 : 1]; | |
66530c61 | 1067 | if (alp_ctx.ctxs[f->protomap][f->alproto].logger == true) { |
429c6388 AS |
1068 | active_id = (log_id < inspect_id) ? log_id : inspect_id; |
1069 | } else { | |
1070 | active_id = inspect_id; | |
d9686fae | 1071 | } |
d9686fae | 1072 | |
429c6388 | 1073 | SCReturnCT(active_id, "uint64_t"); |
d9686fae AS |
1074 | } |
1075 | ||
bcfa484b VJ |
1076 | int AppLayerParserSupportsFiles(uint8_t ipproto, AppProto alproto) |
1077 | { | |
1078 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetFiles != NULL) | |
1079 | return TRUE; | |
1080 | return FALSE; | |
1081 | } | |
1082 | ||
1cf02560 VJ |
1083 | int AppLayerParserSupportsTxDetectState(uint8_t ipproto, AppProto alproto) |
1084 | { | |
1085 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState != NULL) | |
1086 | return TRUE; | |
1087 | return FALSE; | |
1088 | } | |
1089 | ||
1090 | DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx) | |
1091 | { | |
1092 | SCEnter(); | |
1093 | DetectEngineState *s; | |
1094 | s = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState(tx); | |
1095 | SCReturnPtr(s, "DetectEngineState"); | |
1096 | } | |
1097 | ||
3148ff34 | 1098 | int AppLayerParserSetTxDetectState(const Flow *f, |
7548944b | 1099 | void *tx, DetectEngineState *s) |
1cf02560 VJ |
1100 | { |
1101 | int r; | |
1102 | SCEnter(); | |
3148ff34 | 1103 | if ((alp_ctx.ctxs[f->protomap][f->alproto].GetTxDetectState(tx) != NULL)) |
1cf02560 | 1104 | SCReturnInt(-EBUSY); |
7548944b | 1105 | r = alp_ctx.ctxs[f->protomap][f->alproto].SetTxDetectState(tx, s); |
1cf02560 VJ |
1106 | SCReturnInt(r); |
1107 | } | |
1108 | ||
daeb8fd3 VJ |
1109 | uint64_t AppLayerParserGetTxDetectFlags(uint8_t ipproto, AppProto alproto, void *tx, uint8_t dir) |
1110 | { | |
1111 | SCEnter(); | |
1112 | uint64_t flags = 0; | |
1113 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectFlags != NULL) { | |
1114 | flags = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectFlags(tx, dir); | |
1115 | } | |
1116 | SCReturnUInt(flags); | |
1117 | } | |
1118 | ||
1119 | void AppLayerParserSetTxDetectFlags(uint8_t ipproto, AppProto alproto, void *tx, uint8_t dir, uint64_t flags) | |
1120 | { | |
1121 | SCEnter(); | |
1122 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectFlags != NULL) { | |
1123 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectFlags(tx, dir, flags); | |
1124 | } | |
1125 | SCReturn; | |
1126 | } | |
1127 | ||
429c6388 AS |
1128 | /***** General *****/ |
1129 | ||
675fa564 | 1130 | int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, |
429c6388 | 1131 | uint8_t flags, uint8_t *input, uint32_t input_len) |
d9686fae | 1132 | { |
429c6388 | 1133 | SCEnter(); |
a77b9b36 VJ |
1134 | #ifdef DEBUG_VALIDATION |
1135 | BUG_ON(f->protomap != FlowGetProtoMapping(f->proto)); | |
1136 | #endif | |
cd0627cd | 1137 | AppLayerParserState *pstate = NULL; |
a77b9b36 | 1138 | AppLayerParserProtoCtx *p = &alp_ctx.ctxs[f->protomap][alproto]; |
429c6388 | 1139 | void *alstate = NULL; |
a194dfbd | 1140 | uint64_t p_tx_cnt = 0; |
d9686fae | 1141 | |
429c6388 AS |
1142 | /* we don't have the parser registered for this protocol */ |
1143 | if (p->StateAlloc == NULL) | |
1144 | goto end; | |
d9686fae | 1145 | |
429c6388 | 1146 | if (flags & STREAM_GAP) { |
c8fb9bcb | 1147 | if (!(p->option_flags & APP_LAYER_PARSER_OPT_ACCEPT_GAPS)) { |
c862bbdc JI |
1148 | SCLogDebug("app-layer parser does not accept gaps"); |
1149 | if (f->alstate != NULL) { | |
1150 | AppLayerParserStreamTruncated(f->proto, alproto, f->alstate, | |
1151 | flags); | |
1152 | } | |
1153 | goto error; | |
1154 | } | |
d9686fae | 1155 | } |
d9686fae | 1156 | |
429c6388 AS |
1157 | /* Get the parser state (if any) */ |
1158 | pstate = f->alparser; | |
1159 | if (pstate == NULL) { | |
8527b8e0 | 1160 | f->alparser = pstate = AppLayerParserStateAlloc(); |
429c6388 AS |
1161 | if (pstate == NULL) |
1162 | goto error; | |
d9686fae AS |
1163 | } |
1164 | ||
429c6388 | 1165 | if (flags & STREAM_EOF) |
8527b8e0 | 1166 | AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_EOF); |
7c31a232 | 1167 | |
429c6388 AS |
1168 | alstate = f->alstate; |
1169 | if (alstate == NULL) { | |
1170 | f->alstate = alstate = p->StateAlloc(); | |
1171 | if (alstate == NULL) | |
1172 | goto error; | |
1173 | SCLogDebug("alloced new app layer state %p (name %s)", | |
1174 | alstate, AppLayerGetProtoName(f->alproto)); | |
1175 | } else { | |
1176 | SCLogDebug("using existing app layer state %p (name %s))", | |
1177 | alstate, AppLayerGetProtoName(f->alproto)); | |
6e0d98d9 | 1178 | } |
429c6388 | 1179 | |
a194dfbd | 1180 | if (AppLayerParserProtocolIsTxAware(f->proto, alproto)) { |
5c01b409 | 1181 | p_tx_cnt = AppLayerParserGetTxCnt(f, f->alstate); |
a194dfbd EL |
1182 | } |
1183 | ||
429c6388 | 1184 | /* invoke the recursive parser, but only on data. We may get empty msgs on EOF */ |
cf9ff6ad | 1185 | if (input_len > 0 || (flags & STREAM_EOF)) { |
429c6388 AS |
1186 | /* invoke the parser */ |
1187 | if (p->Parser[(flags & STREAM_TOSERVER) ? 0 : 1](f, alstate, pstate, | |
1188 | input, input_len, | |
7bc3c3ac VJ |
1189 | alp_tctx->alproto_local_storage[f->protomap][alproto], |
1190 | flags) < 0) | |
59327e0f VJ |
1191 | { |
1192 | goto error; | |
1193 | } | |
6e0d98d9 | 1194 | } |
429c6388 AS |
1195 | |
1196 | /* set the packets to no inspection and reassembly if required */ | |
1197 | if (pstate->flags & APP_LAYER_PARSER_NO_INSPECTION) { | |
1198 | AppLayerParserSetEOF(pstate); | |
1199 | FlowSetNoPayloadInspectionFlag(f); | |
429c6388 | 1200 | |
c1558f5a VJ |
1201 | if (f->proto == IPPROTO_TCP) { |
1202 | StreamTcpDisableAppLayer(f); | |
1203 | ||
1204 | /* Set the no reassembly flag for both the stream in this TcpSession */ | |
1205 | if (pstate->flags & APP_LAYER_PARSER_NO_REASSEMBLY) { | |
1206 | /* Used only if it's TCP */ | |
1207 | TcpSession *ssn = f->protoctx; | |
1208 | if (ssn != NULL) { | |
1209 | StreamTcpSetSessionNoReassemblyFlag(ssn, | |
1210 | flags & STREAM_TOCLIENT ? 1 : 0); | |
1211 | StreamTcpSetSessionNoReassemblyFlag(ssn, | |
1212 | flags & STREAM_TOSERVER ? 1 : 0); | |
1213 | } | |
429c6388 | 1214 | } |
26eb49d7 EL |
1215 | /* Set the bypass flag for both the stream in this TcpSession */ |
1216 | if (pstate->flags & APP_LAYER_PARSER_BYPASS_READY) { | |
1217 | /* Used only if it's TCP */ | |
1218 | TcpSession *ssn = f->protoctx; | |
1219 | if (ssn != NULL) { | |
1220 | StreamTcpSetSessionBypassFlag(ssn); | |
1221 | } | |
1222 | } | |
429c6388 | 1223 | } |
7f8fb0f0 AS |
1224 | } |
1225 | ||
26169ad8 | 1226 | /* In cases like HeartBleed for TLS we need to inspect AppLayer but not Payload */ |
3543150f | 1227 | if (!(f->flags & FLOW_NOPAYLOAD_INSPECTION) && pstate->flags & APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD) { |
26169ad8 | 1228 | FlowSetNoPayloadInspectionFlag(f); |
3543150f VJ |
1229 | /* Set the no reassembly flag for both the stream in this TcpSession */ |
1230 | if (f->proto == IPPROTO_TCP) { | |
1231 | /* Used only if it's TCP */ | |
1232 | TcpSession *ssn = f->protoctx; | |
1233 | if (ssn != NULL) { | |
1234 | StreamTcpSetDisableRawReassemblyFlag(ssn, 0); | |
1235 | StreamTcpSetDisableRawReassemblyFlag(ssn, 1); | |
3543150f VJ |
1236 | } |
1237 | } | |
26169ad8 WM |
1238 | } |
1239 | ||
a194dfbd EL |
1240 | if (AppLayerParserProtocolIsTxAware(f->proto, alproto)) { |
1241 | if (likely(tv)) { | |
5c01b409 | 1242 | uint64_t cur_tx_cnt = AppLayerParserGetTxCnt(f, f->alstate); |
a194dfbd EL |
1243 | if (cur_tx_cnt > p_tx_cnt) { |
1244 | AppLayerIncTxCounter(tv, f, cur_tx_cnt - p_tx_cnt); | |
1245 | } | |
1246 | } | |
1247 | } | |
429c6388 AS |
1248 | |
1249 | /* stream truncated, inform app layer */ | |
1250 | if (flags & STREAM_DEPTH) | |
1251 | AppLayerParserStreamTruncated(f->proto, alproto, alstate, flags); | |
1252 | ||
1253 | end: | |
1254 | SCReturnInt(0); | |
6e0d98d9 | 1255 | error: |
a77b9b36 VJ |
1256 | /* Set the no app layer inspection flag for both |
1257 | * the stream in this Flow */ | |
c1558f5a VJ |
1258 | if (f->proto == IPPROTO_TCP) { |
1259 | StreamTcpDisableAppLayer(f); | |
1260 | } | |
a77b9b36 | 1261 | AppLayerParserSetEOF(pstate); |
429c6388 | 1262 | SCReturnInt(-1); |
7c31a232 AS |
1263 | } |
1264 | ||
9634e60e | 1265 | void AppLayerParserSetEOF(AppLayerParserState *pstate) |
7c31a232 | 1266 | { |
429c6388 | 1267 | SCEnter(); |
7c31a232 | 1268 | |
429c6388 AS |
1269 | if (pstate == NULL) |
1270 | goto end; | |
1271 | ||
8527b8e0 | 1272 | AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_EOF); |
429c6388 AS |
1273 | |
1274 | end: | |
1275 | SCReturn; | |
432c3317 AS |
1276 | } |
1277 | ||
af51e0f5 VJ |
1278 | /* return true if there are app parser decoder events. These are |
1279 | * only the ones that are set during protocol detection. */ | |
1280 | bool AppLayerParserHasDecoderEvents(AppLayerParserState *pstate) | |
432c3317 | 1281 | { |
429c6388 | 1282 | SCEnter(); |
432c3317 | 1283 | |
af51e0f5 VJ |
1284 | if (pstate == NULL) |
1285 | return false; | |
7c31a232 | 1286 | |
af51e0f5 | 1287 | const AppLayerDecoderEvents *decoder_events = AppLayerParserGetDecoderEvents(pstate); |
429c6388 | 1288 | if (decoder_events && decoder_events->cnt) |
af51e0f5 | 1289 | return true; |
429c6388 AS |
1290 | |
1291 | /* if we have reached here, we don't have events */ | |
948dee9a | 1292 | return false; |
d9686fae AS |
1293 | } |
1294 | ||
01913f6a VJ |
1295 | /** \brief simpler way to globally test if a alproto is registered |
1296 | * and fully enabled in the configuration. | |
1297 | */ | |
1298 | int AppLayerParserIsTxAware(AppProto alproto) | |
1299 | { | |
1300 | return (alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto] | |
1301 | .StateGetProgressCompletionStatus != NULL); | |
1302 | } | |
1303 | ||
b2d420be VJ |
1304 | int AppLayerParserProtocolIsTxAware(uint8_t ipproto, AppProto alproto) |
1305 | { | |
1306 | SCEnter(); | |
1307 | int ipproto_map = FlowGetProtoMapping(ipproto); | |
1308 | int r = (alp_ctx.ctxs[ipproto_map][alproto].StateGetTx == NULL) ? 0 : 1; | |
1309 | SCReturnInt(r); | |
1310 | } | |
1311 | ||
5cdeadb3 | 1312 | int AppLayerParserProtocolIsTxEventAware(uint8_t ipproto, AppProto alproto) |
d9686fae | 1313 | { |
429c6388 AS |
1314 | SCEnter(); |
1315 | int ipproto_map = FlowGetProtoMapping(ipproto); | |
3967bd55 | 1316 | int r = (alp_ctx.ctxs[ipproto_map][alproto].StateGetEvents == NULL) ? 0 : 1; |
1cbd1cdf | 1317 | SCReturnInt(r); |
429c6388 | 1318 | } |
432c3317 | 1319 | |
5cdeadb3 | 1320 | int AppLayerParserProtocolSupportsTxs(uint8_t ipproto, AppProto alproto) |
429c6388 AS |
1321 | { |
1322 | SCEnter(); | |
1323 | int ipproto_map = FlowGetProtoMapping(ipproto); | |
1cbd1cdf VJ |
1324 | int r = (alp_ctx.ctxs[ipproto_map][alproto].StateTransactionFree == NULL) ? 0 : 1; |
1325 | SCReturnInt(r); | |
432c3317 AS |
1326 | } |
1327 | ||
078ff0c0 VJ |
1328 | int AppLayerParserProtocolHasLogger(uint8_t ipproto, AppProto alproto) |
1329 | { | |
1330 | SCEnter(); | |
1331 | int ipproto_map = FlowGetProtoMapping(ipproto); | |
66530c61 | 1332 | int r = (alp_ctx.ctxs[ipproto_map][alproto].logger == false) ? 0 : 1; |
078ff0c0 VJ |
1333 | SCReturnInt(r); |
1334 | } | |
1335 | ||
bca0cd71 VJ |
1336 | LoggerId AppLayerParserProtocolGetLoggerBits(uint8_t ipproto, AppProto alproto) |
1337 | { | |
1338 | SCEnter(); | |
1339 | const int ipproto_map = FlowGetProtoMapping(ipproto); | |
1340 | LoggerId r = alp_ctx.ctxs[ipproto_map][alproto].logger_bits; | |
1341 | SCReturnUInt(r); | |
1342 | } | |
1343 | ||
2d223b69 | 1344 | void AppLayerParserTriggerRawStreamReassembly(Flow *f, int direction) |
432c3317 | 1345 | { |
429c6388 | 1346 | SCEnter(); |
432c3317 | 1347 | |
2d223b69 | 1348 | SCLogDebug("f %p tcp %p direction %d", f, f ? f->protoctx : NULL, direction); |
429c6388 | 1349 | if (f != NULL && f->protoctx != NULL) |
2d223b69 | 1350 | StreamTcpReassembleTriggerRawReassembly(f->protoctx, direction); |
d9686fae | 1351 | |
429c6388 | 1352 | SCReturn; |
7c31a232 AS |
1353 | } |
1354 | ||
b160c49e GL |
1355 | void AppLayerParserSetStreamDepth(uint8_t ipproto, AppProto alproto, uint32_t stream_depth) |
1356 | { | |
1357 | SCEnter(); | |
1358 | ||
1359 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].stream_depth = stream_depth; | |
c8fb9bcb VJ |
1360 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].internal_flags |= |
1361 | APP_LAYER_PARSER_INT_STREAM_DEPTH_SET; | |
b160c49e GL |
1362 | |
1363 | SCReturn; | |
1364 | } | |
1365 | ||
3148ff34 | 1366 | uint32_t AppLayerParserGetStreamDepth(const Flow *f) |
b160c49e | 1367 | { |
3148ff34 | 1368 | SCReturnInt(alp_ctx.ctxs[f->protomap][f->alproto].stream_depth); |
b160c49e GL |
1369 | } |
1370 | ||
429c6388 AS |
1371 | /***** Cleanup *****/ |
1372 | ||
3148ff34 | 1373 | void AppLayerParserStateCleanup(const Flow *f, void *alstate, |
9634e60e | 1374 | AppLayerParserState *pstate) |
7c31a232 | 1375 | { |
429c6388 | 1376 | SCEnter(); |
7c31a232 | 1377 | |
3148ff34 | 1378 | AppLayerParserProtoCtx *ctx = &alp_ctx.ctxs[f->protomap][f->alproto]; |
7c31a232 | 1379 | |
429c6388 AS |
1380 | if (ctx->StateFree != NULL && alstate != NULL) |
1381 | ctx->StateFree(alstate); | |
7c31a232 | 1382 | |
429c6388 AS |
1383 | /* free the app layer parser api state */ |
1384 | if (pstate != NULL) | |
8527b8e0 | 1385 | AppLayerParserStateFree(pstate); |
432c3317 | 1386 | |
429c6388 AS |
1387 | SCReturn; |
1388 | } | |
432c3317 | 1389 | |
ed172985 VJ |
1390 | static void ValidateParserProtoDump(AppProto alproto, uint8_t ipproto) |
1391 | { | |
1392 | uint8_t map = FlowGetProtoMapping(ipproto); | |
1393 | const AppLayerParserProtoCtx *ctx = &alp_ctx.ctxs[map][alproto]; | |
1394 | const AppLayerParserProtoCtx *ctx_def = &alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto]; | |
1395 | printf("ERROR: incomplete app-layer registration\n"); | |
1396 | printf("AppLayer protocol %s ipproto %u\n", AppProtoToString(alproto), ipproto); | |
c8fb9bcb | 1397 | printf("- option flags %"PRIx32"\n", ctx->option_flags); |
ed172985 VJ |
1398 | printf("- first_data_dir %"PRIx8"\n", ctx->first_data_dir); |
1399 | printf("Mandatory:\n"); | |
1400 | printf("- Parser[0] %p Parser[1] %p\n", ctx->Parser[0], ctx->Parser[1]); | |
1401 | printf("- StateAlloc %p StateFree %p\n", ctx->StateAlloc, ctx->StateFree); | |
1402 | printf("- StateGetTx %p StateGetTxCnt %p StateTransactionFree %p\n", | |
1403 | ctx->StateGetTx, ctx->StateGetTxCnt, ctx->StateTransactionFree); | |
1404 | printf("- StateGetProgress %p StateGetProgressCompletionStatus %p\n", ctx->StateGetProgress, ctx_def->StateGetProgressCompletionStatus); | |
e9305131 | 1405 | printf("- GetTxDetectState %p SetTxDetectState %p\n", ctx->GetTxDetectState, ctx->SetTxDetectState); |
ed172985 VJ |
1406 | printf("Optional:\n"); |
1407 | printf("- LocalStorageAlloc %p LocalStorageFree %p\n", ctx->LocalStorageAlloc, ctx->LocalStorageFree); | |
1408 | printf("- StateGetTxLogged %p StateSetTxLogged %p\n", ctx->StateGetTxLogged, ctx->StateSetTxLogged); | |
c4115196 | 1409 | printf("- StateGetEvents %p StateGetEventInfo %p\n", ctx->StateGetEvents, ctx->StateGetEventInfo); |
ed172985 VJ |
1410 | } |
1411 | ||
1412 | #define BOTH_SET(a, b) ((a) != NULL && (b) != NULL) | |
1413 | #define BOTH_SET_OR_BOTH_UNSET(a, b) (((a) == NULL && (b) == NULL) || ((a) != NULL && (b) != NULL)) | |
1414 | #define THREE_SET_OR_THREE_UNSET(a, b, c) (((a) == NULL && (b) == NULL && (c) == NULL) || ((a) != NULL && (b) != NULL && (c) != NULL)) | |
1415 | ||
1416 | static void ValidateParserProto(AppProto alproto, uint8_t ipproto) | |
1417 | { | |
1418 | uint8_t map = FlowGetProtoMapping(ipproto); | |
1419 | const AppLayerParserProtoCtx *ctx = &alp_ctx.ctxs[map][alproto]; | |
1420 | const AppLayerParserProtoCtx *ctx_def = &alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto]; | |
1421 | ||
1422 | if (ctx->Parser[0] == NULL && ctx->Parser[1] == NULL) | |
1423 | return; | |
1424 | ||
1425 | if (!(BOTH_SET(ctx->Parser[0], ctx->Parser[1]))) { | |
1426 | goto bad; | |
1427 | } | |
1428 | if (!(BOTH_SET(ctx->StateFree, ctx->StateAlloc))) { | |
1429 | goto bad; | |
1430 | } | |
1431 | if (!(THREE_SET_OR_THREE_UNSET(ctx->StateGetTx, ctx->StateGetTxCnt, ctx->StateTransactionFree))) { | |
1432 | goto bad; | |
1433 | } | |
1434 | /* special case: StateGetProgressCompletionStatus is used from 'default'. */ | |
1435 | if (!(BOTH_SET(ctx->StateGetProgress, ctx_def->StateGetProgressCompletionStatus))) { | |
1436 | goto bad; | |
1437 | } | |
1438 | /* local storage is optional, but needs both set if used */ | |
1439 | if (!(BOTH_SET_OR_BOTH_UNSET(ctx->LocalStorageAlloc, ctx->LocalStorageFree))) { | |
1440 | goto bad; | |
1441 | } | |
1442 | if (!(BOTH_SET_OR_BOTH_UNSET(ctx->StateGetTxLogged, ctx->StateSetTxLogged))) { | |
1443 | goto bad; | |
1444 | } | |
e9305131 | 1445 | if (!(BOTH_SET(ctx->GetTxDetectState, ctx->SetTxDetectState))) { |
ed172985 VJ |
1446 | goto bad; |
1447 | } | |
1448 | /* TODO: not yet mandatory to use StateHasTxDetectState | |
1449 | if (!(THREE_SET_OR_THREE_UNSET(ctx->GetTxDetectState, ctx->SetTxDetectState, ctx->StateHasTxDetectState))) { | |
1450 | goto bad; | |
1451 | } | |
1452 | */ | |
1453 | ||
1454 | return; | |
1455 | bad: | |
1456 | ValidateParserProtoDump(alproto, ipproto); | |
1457 | exit(EXIT_FAILURE); | |
1458 | } | |
1459 | #undef BOTH_SET | |
1460 | #undef BOTH_SET_OR_BOTH_UNSET | |
1461 | #undef THREE_SET_OR_THREE_UNSET | |
1462 | ||
1463 | static void ValidateParser(AppProto alproto) | |
1464 | { | |
1465 | ValidateParserProto(alproto, IPPROTO_TCP); | |
1466 | ValidateParserProto(alproto, IPPROTO_UDP); | |
1467 | } | |
1468 | ||
1469 | static void ValidateParsers(void) | |
1470 | { | |
1471 | AppProto p = 0; | |
1472 | for ( ; p < ALPROTO_MAX; p++) { | |
1473 | ValidateParser(p); | |
1474 | } | |
1475 | } | |
432c3317 | 1476 | |
429c6388 AS |
1477 | void AppLayerParserRegisterProtocolParsers(void) |
1478 | { | |
1479 | SCEnter(); | |
d9686fae | 1480 | |
429c6388 AS |
1481 | RegisterHTPParsers(); |
1482 | RegisterSSLParsers(); | |
429c6388 AS |
1483 | RegisterDCERPCParsers(); |
1484 | RegisterDCERPCUDPParsers(); | |
c2cb155e | 1485 | RegisterSMBParsers(); |
429c6388 | 1486 | RegisterFTPParsers(); |
429c6388 | 1487 | RegisterSSHParsers(); |
429c6388 AS |
1488 | RegisterSMTPParsers(); |
1489 | RegisterDNSUDPParsers(); | |
1490 | RegisterDNSTCPParsers(); | |
5a040995 | 1491 | RegisterModbusParsers(); |
a3ffebd8 | 1492 | RegisterENIPUDPParsers(); |
1493 | RegisterENIPTCPParsers(); | |
bbaa79b8 | 1494 | RegisterDNP3Parsers(); |
0d79181d VJ |
1495 | RegisterNFSTCPParsers(); |
1496 | RegisterNFSUDPParsers(); | |
efe11dc3 | 1497 | RegisterNTPParsers(); |
b9cf49e9 | 1498 | RegisterTFTPParsers(); |
c99b9462 | 1499 | RegisterIKEV2Parsers(); |
77f0c11c | 1500 | RegisterKRB5Parsers(); |
9210d874 | 1501 | RegisterDHCPParsers(); |
96dc20ab | 1502 | RegisterTemplateRustParsers(); |
c1b92126 | 1503 | RegisterTemplateParsers(); |
432c3317 | 1504 | |
429c6388 AS |
1505 | /** IMAP */ |
1506 | AppLayerProtoDetectRegisterProtocol(ALPROTO_IMAP, "imap"); | |
1507 | if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", "imap")) { | |
1508 | if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_IMAP, | |
1509 | "1|20|capability", 12, 0, STREAM_TOSERVER) < 0) | |
1510 | { | |
1511 | SCLogInfo("imap proto registration failure\n"); | |
1512 | exit(EXIT_FAILURE); | |
d9686fae | 1513 | } |
429c6388 AS |
1514 | } else { |
1515 | SCLogInfo("Protocol detection and parser disabled for %s protocol.", | |
1516 | "imap"); | |
d9686fae | 1517 | } |
429c6388 AS |
1518 | |
1519 | /** MSN Messenger */ | |
1520 | AppLayerProtoDetectRegisterProtocol(ALPROTO_MSN, "msn"); | |
1521 | if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", "msn")) { | |
1522 | if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_MSN, | |
1523 | "msn", 10, 6, STREAM_TOSERVER) < 0) | |
1524 | { | |
1525 | SCLogInfo("msn proto registration failure\n"); | |
1526 | exit(EXIT_FAILURE); | |
7c31a232 | 1527 | } |
d9686fae | 1528 | } else { |
429c6388 AS |
1529 | SCLogInfo("Protocol detection and parser disabled for %s protocol.", |
1530 | "msn"); | |
7c31a232 | 1531 | } |
432c3317 | 1532 | |
ed172985 | 1533 | ValidateParsers(); |
432c3317 AS |
1534 | return; |
1535 | } | |
1536 | ||
0d7159b5 | 1537 | |
9634e60e | 1538 | void AppLayerParserStateSetFlag(AppLayerParserState *pstate, uint8_t flag) |
429c6388 AS |
1539 | { |
1540 | SCEnter(); | |
9634e60e | 1541 | pstate->flags |= flag; |
429c6388 | 1542 | SCReturn; |
0d7159b5 AS |
1543 | } |
1544 | ||
9634e60e | 1545 | int AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint8_t flag) |
0d7159b5 | 1546 | { |
429c6388 | 1547 | SCEnter(); |
9634e60e | 1548 | SCReturnInt(pstate->flags & flag); |
0d7159b5 AS |
1549 | } |
1550 | ||
429c6388 | 1551 | |
5cdeadb3 | 1552 | void AppLayerParserStreamTruncated(uint8_t ipproto, AppProto alproto, void *alstate, |
429c6388 | 1553 | uint8_t direction) |
d9686fae | 1554 | { |
429c6388 | 1555 | SCEnter(); |
432c3317 | 1556 | |
429c6388 AS |
1557 | |
1558 | if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].Truncate != NULL) | |
1559 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].Truncate(alstate, direction); | |
1560 | ||
1561 | SCReturn; | |
7c31a232 AS |
1562 | } |
1563 | ||
429c6388 | 1564 | #ifdef DEBUG |
9634e60e | 1565 | void AppLayerParserStatePrintDetails(AppLayerParserState *pstate) |
7c31a232 | 1566 | { |
429c6388 | 1567 | SCEnter(); |
980934d6 | 1568 | |
429c6388 AS |
1569 | if (pstate == NULL) |
1570 | SCReturn; | |
7c31a232 | 1571 | |
9634e60e | 1572 | AppLayerParserState *p = pstate; |
429c6388 AS |
1573 | SCLogDebug("AppLayerParser parser state information for parser state p(%p). " |
1574 | "p->inspect_id[0](%"PRIu64"), " | |
1575 | "p->inspect_id[1](%"PRIu64"), " | |
1576 | "p->log_id(%"PRIu64"), " | |
429c6388 AS |
1577 | "p->decoder_events(%p).", |
1578 | pstate, p->inspect_id[0], p->inspect_id[1], p->log_id, | |
e24eb0f2 | 1579 | p->decoder_events); |
7c31a232 | 1580 | |
429c6388 | 1581 | SCReturn; |
7c31a232 | 1582 | } |
429c6388 AS |
1583 | #endif |
1584 | ||
077ac816 | 1585 | #ifdef AFLFUZZ_APPLAYER |
4683b0e6 | 1586 | int AppLayerParserRequestFromFile(uint8_t ipproto, AppProto alproto, char *filename) |
077ac816 | 1587 | { |
71c3141e | 1588 | bool do_dump = (getenv("SC_AFL_DUMP_FILES") != NULL); |
31daf435 VJ |
1589 | struct timeval ts; |
1590 | memset(&ts, 0, sizeof(ts)); | |
1591 | gettimeofday(&ts, NULL); | |
1592 | ||
077ac816 VJ |
1593 | int result = 1; |
1594 | Flow *f = NULL; | |
1595 | TcpSession ssn; | |
1596 | AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); | |
1597 | ||
1598 | memset(&ssn, 0, sizeof(ssn)); | |
1599 | ||
1600 | f = SCCalloc(1, sizeof(Flow)); | |
1601 | if (f == NULL) | |
1602 | goto end; | |
1603 | FLOW_INITIALIZE(f); | |
1604 | ||
1605 | f->flags |= FLOW_IPV4; | |
1606 | f->src.addr_data32[0] = 0x01020304; | |
1607 | f->dst.addr_data32[0] = 0x05060708; | |
1608 | f->sp = 10000; | |
1609 | f->dp = 80; | |
1610 | f->protoctx = &ssn; | |
4683b0e6 VJ |
1611 | f->proto = ipproto; |
1612 | f->protomap = FlowGetProtoMapping(f->proto); | |
077ac816 VJ |
1613 | f->alproto = alproto; |
1614 | ||
31daf435 VJ |
1615 | uint8_t buffer[65536]; |
1616 | uint32_t cnt = 0; | |
077ac816 | 1617 | |
45d87d66 MK |
1618 | #ifdef AFLFUZZ_PERSISTANT_MODE |
1619 | while (__AFL_LOOP(1000)) { | |
1620 | /* reset state */ | |
1621 | memset(buffer, 0, sizeof(buffer)); | |
1622 | #endif /* AFLFUZZ_PERSISTANT_MODE */ | |
077ac816 | 1623 | |
45d87d66 MK |
1624 | FILE *fp = fopen(filename, "r"); |
1625 | BUG_ON(fp == NULL); | |
077ac816 | 1626 | |
45d87d66 MK |
1627 | int start = 1; |
1628 | while (1) { | |
1629 | int done = 0; | |
c89ce170 VJ |
1630 | size_t size = fread(&buffer, 1, sizeof(buffer), fp); |
1631 | if (size < sizeof(buffer)) | |
45d87d66 | 1632 | done = 1; |
077ac816 | 1633 | |
71c3141e VJ |
1634 | if (do_dump) { |
1635 | char outfilename[256]; | |
1636 | snprintf(outfilename, sizeof(outfilename), "dump/%u-%u.%u", | |
1637 | (unsigned int)ts.tv_sec, (unsigned int)ts.tv_usec, cnt); | |
1638 | FILE *out_fp = fopen(outfilename, "w"); | |
1639 | BUG_ON(out_fp == NULL); | |
1640 | (void)fwrite(buffer, size, 1, out_fp); | |
1641 | fclose(out_fp); | |
1642 | } | |
45d87d66 | 1643 | //SCLogInfo("result %u done %d start %d", (uint)result, done, start); |
077ac816 | 1644 | |
45d87d66 | 1645 | uint8_t flags = STREAM_TOSERVER; |
45d87d66 MK |
1646 | if (start--) { |
1647 | flags |= STREAM_START; | |
1648 | } | |
1649 | if (done) { | |
1650 | flags |= STREAM_EOF; | |
1651 | } | |
1652 | //PrintRawDataFp(stdout, buffer, result); | |
1653 | ||
675fa564 | 1654 | (void)AppLayerParserParse(NULL, alp_tctx, f, alproto, flags, |
c89ce170 | 1655 | buffer, size); |
31daf435 VJ |
1656 | cnt++; |
1657 | ||
45d87d66 MK |
1658 | if (done) |
1659 | break; | |
077ac816 | 1660 | } |
077ac816 | 1661 | |
45d87d66 MK |
1662 | fclose(fp); |
1663 | ||
1664 | #ifdef AFLFUZZ_PERSISTANT_MODE | |
077ac816 | 1665 | } |
45d87d66 | 1666 | #endif /* AFLFUZZ_PERSISTANT_MODE */ |
077ac816 | 1667 | |
71c3141e VJ |
1668 | if (do_dump) { |
1669 | /* if we get here there was no crash, so we can remove our files */ | |
1670 | uint32_t x = 0; | |
1671 | for (x = 0; x < cnt; x++) { | |
1672 | char rmfilename[256]; | |
1673 | snprintf(rmfilename, sizeof(rmfilename), "dump/%u-%u.%u", | |
1674 | (unsigned int)ts.tv_sec, (unsigned int)ts.tv_usec, x); | |
1675 | unlink(rmfilename); | |
1676 | } | |
31daf435 VJ |
1677 | } |
1678 | ||
1679 | result = 0; | |
1680 | ||
1681 | end: | |
1682 | if (alp_tctx != NULL) | |
1683 | AppLayerParserThreadCtxFree(alp_tctx); | |
1684 | if (f != NULL) { | |
1685 | FlowFree(f); | |
1686 | } | |
1687 | return result; | |
1688 | } | |
1689 | ||
1690 | /* load a serie of files generated by DecoderParseDataFromFile() in | |
1691 | * the same order as it was produced. */ | |
1692 | int AppLayerParserRequestFromFileSerie(uint8_t ipproto, AppProto alproto, char *fileprefix) | |
1693 | { | |
1694 | uint32_t cnt = 0; | |
1695 | int start = 1; | |
1696 | int result = 1; | |
1697 | Flow *f = NULL; | |
1698 | TcpSession ssn; | |
1699 | AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); | |
1700 | ||
1701 | memset(&ssn, 0, sizeof(ssn)); | |
1702 | ||
1703 | f = SCCalloc(1, sizeof(Flow)); | |
1704 | if (f == NULL) | |
1705 | goto end; | |
1706 | FLOW_INITIALIZE(f); | |
1707 | ||
1708 | f->flags |= FLOW_IPV4; | |
1709 | f->src.addr_data32[0] = 0x01020304; | |
1710 | f->dst.addr_data32[0] = 0x05060708; | |
1711 | f->sp = 10000; | |
1712 | f->dp = 80; | |
1713 | f->protoctx = &ssn; | |
1714 | f->proto = ipproto; | |
1715 | f->protomap = FlowGetProtoMapping(f->proto); | |
1716 | f->alproto = alproto; | |
1717 | ||
1718 | uint8_t buffer[65536]; | |
1719 | ||
1720 | char filename[256]; | |
1721 | snprintf(filename, sizeof(filename), "dump/%s.%u", fileprefix, cnt); | |
1722 | FILE *fp; | |
1723 | while ((fp = fopen(filename, "r")) != NULL) | |
1724 | { | |
1725 | memset(buffer, 0, sizeof(buffer)); | |
1726 | ||
1727 | size_t size = fread(&buffer, 1, sizeof(buffer), fp); | |
1728 | ||
1729 | uint8_t flags = STREAM_TOSERVER; | |
1730 | if (start--) { | |
1731 | flags |= STREAM_START; | |
1732 | } | |
1733 | ||
1734 | (void)AppLayerParserParse(NULL, alp_tctx, f, alproto, flags, | |
1735 | buffer, size); | |
1736 | ||
1737 | fclose(fp); | |
1738 | cnt++; | |
1739 | ||
1740 | snprintf(filename, sizeof(filename), "dump/%s.%u", fileprefix, cnt); | |
1741 | } | |
1742 | ||
077ac816 | 1743 | result = 0; |
45d87d66 | 1744 | |
077ac816 VJ |
1745 | end: |
1746 | if (alp_tctx != NULL) | |
1747 | AppLayerParserThreadCtxFree(alp_tctx); | |
1748 | if (f != NULL) { | |
1749 | FlowFree(f); | |
1750 | } | |
1751 | return result; | |
1752 | } | |
1753 | ||
4683b0e6 | 1754 | int AppLayerParserFromFile(uint8_t ipproto, AppProto alproto, char *filename) |
077ac816 | 1755 | { |
71c3141e | 1756 | bool do_dump = (getenv("SC_AFL_DUMP_FILES") != NULL); |
31daf435 VJ |
1757 | struct timeval ts; |
1758 | memset(&ts, 0, sizeof(ts)); | |
1759 | gettimeofday(&ts, NULL); | |
1760 | ||
077ac816 VJ |
1761 | int result = 1; |
1762 | Flow *f = NULL; | |
1763 | TcpSession ssn; | |
1764 | AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); | |
1765 | ||
1766 | memset(&ssn, 0, sizeof(ssn)); | |
1767 | ||
1768 | f = SCCalloc(1, sizeof(Flow)); | |
1769 | if (f == NULL) | |
1770 | goto end; | |
1771 | FLOW_INITIALIZE(f); | |
1772 | ||
1773 | f->flags |= FLOW_IPV4; | |
1774 | f->src.addr_data32[0] = 0x01020304; | |
1775 | f->dst.addr_data32[0] = 0x05060708; | |
1776 | f->sp = 10000; | |
1777 | f->dp = 80; | |
1778 | f->protoctx = &ssn; | |
4683b0e6 VJ |
1779 | f->proto = ipproto; |
1780 | f->protomap = FlowGetProtoMapping(f->proto); | |
077ac816 VJ |
1781 | f->alproto = alproto; |
1782 | ||
31daf435 VJ |
1783 | uint8_t buffer[65536]; |
1784 | uint32_t cnt = 0; | |
077ac816 | 1785 | |
45d87d66 MK |
1786 | #ifdef AFLFUZZ_PERSISTANT_MODE |
1787 | while (__AFL_LOOP(1000)) { | |
1788 | /* reset state */ | |
1789 | memset(buffer, 0, sizeof(buffer)); | |
1790 | #endif /* AFLFUZZ_PERSISTANT_MODE */ | |
1791 | ||
1792 | FILE *fp = fopen(filename, "r"); | |
1793 | BUG_ON(fp == NULL); | |
1794 | ||
1795 | int start = 1; | |
1796 | int flip = 0; | |
1797 | while (1) { | |
1798 | int done = 0; | |
c89ce170 VJ |
1799 | size_t size = fread(&buffer, 1, sizeof(buffer), fp); |
1800 | if (size < sizeof(buffer)) | |
45d87d66 | 1801 | done = 1; |
71c3141e VJ |
1802 | if (do_dump) { |
1803 | char outfilename[256]; | |
1804 | snprintf(outfilename, sizeof(outfilename), "dump/%u-%u.%u", | |
1805 | (unsigned int)ts.tv_sec, (unsigned int)ts.tv_usec, cnt); | |
1806 | FILE *out_fp = fopen(outfilename, "w"); | |
1807 | BUG_ON(out_fp == NULL); | |
1808 | (void)fwrite(buffer, size, 1, out_fp); | |
1809 | fclose(out_fp); | |
1810 | } | |
45d87d66 MK |
1811 | //SCLogInfo("result %u done %d start %d", (uint)result, done, start); |
1812 | ||
1813 | uint8_t flags = 0; | |
1814 | if (flip) { | |
1815 | flags = STREAM_TOCLIENT; | |
1816 | flip = 0; | |
1817 | } else { | |
1818 | flags = STREAM_TOSERVER; | |
1819 | flip = 1; | |
1820 | } | |
077ac816 | 1821 | |
45d87d66 MK |
1822 | if (start--) { |
1823 | flags |= STREAM_START; | |
1824 | } | |
1825 | if (done) { | |
1826 | flags |= STREAM_EOF; | |
1827 | } | |
1828 | //PrintRawDataFp(stdout, buffer, result); | |
077ac816 | 1829 | |
675fa564 | 1830 | (void)AppLayerParserParse(NULL, alp_tctx, f, alproto, flags, |
c89ce170 | 1831 | buffer, size); |
31daf435 VJ |
1832 | |
1833 | cnt++; | |
1834 | ||
45d87d66 MK |
1835 | if (done) |
1836 | break; | |
077ac816 VJ |
1837 | } |
1838 | ||
45d87d66 | 1839 | fclose(fp); |
077ac816 | 1840 | |
45d87d66 | 1841 | #ifdef AFLFUZZ_PERSISTANT_MODE |
077ac816 | 1842 | } |
45d87d66 | 1843 | #endif /* AFLFUZZ_PERSISTANT_MODE */ |
077ac816 | 1844 | |
71c3141e VJ |
1845 | if (do_dump) { |
1846 | /* if we get here there was no crash, so we can remove our files */ | |
1847 | uint32_t x = 0; | |
1848 | for (x = 0; x < cnt; x++) { | |
1849 | char rmfilename[256]; | |
1850 | snprintf(rmfilename, sizeof(rmfilename), "dump/%u-%u.%u", | |
1851 | (unsigned int)ts.tv_sec, (unsigned int)ts.tv_usec, x); | |
1852 | unlink(rmfilename); | |
1853 | } | |
31daf435 VJ |
1854 | } |
1855 | ||
1856 | result = 0; | |
1857 | end: | |
1858 | if (alp_tctx != NULL) | |
1859 | AppLayerParserThreadCtxFree(alp_tctx); | |
1860 | if (f != NULL) { | |
1861 | FlowFree(f); | |
1862 | } | |
1863 | return result; | |
1864 | } | |
1865 | ||
1866 | /* load a serie of files generated by DecoderParseDataFromFile() in | |
1867 | * the same order as it was produced. */ | |
1868 | int AppLayerParserFromFileSerie(uint8_t ipproto, AppProto alproto, char *fileprefix) | |
1869 | { | |
1870 | uint32_t cnt = 0; | |
1871 | int start = 1; | |
1872 | int result = 1; | |
1873 | Flow *f = NULL; | |
1874 | TcpSession ssn; | |
1875 | AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); | |
1876 | ||
1877 | memset(&ssn, 0, sizeof(ssn)); | |
1878 | ||
1879 | f = SCCalloc(1, sizeof(Flow)); | |
1880 | if (f == NULL) | |
1881 | goto end; | |
1882 | FLOW_INITIALIZE(f); | |
1883 | ||
1884 | f->flags |= FLOW_IPV4; | |
1885 | f->src.addr_data32[0] = 0x01020304; | |
1886 | f->dst.addr_data32[0] = 0x05060708; | |
1887 | f->sp = 10000; | |
1888 | f->dp = 80; | |
1889 | f->protoctx = &ssn; | |
1890 | f->proto = ipproto; | |
1891 | f->protomap = FlowGetProtoMapping(f->proto); | |
1892 | f->alproto = alproto; | |
1893 | ||
1894 | uint8_t buffer[65536]; | |
1895 | int flip = 0; | |
1896 | char filename[256]; | |
1897 | snprintf(filename, sizeof(filename), "dump/%s.%u", fileprefix, cnt); | |
1898 | FILE *fp; | |
1899 | while ((fp = fopen(filename, "r")) != NULL) | |
1900 | { | |
1901 | memset(buffer, 0, sizeof(buffer)); | |
1902 | ||
1903 | size_t size = fread(&buffer, 1, sizeof(buffer), fp); | |
1904 | ||
1905 | uint8_t flags = 0; | |
1906 | if (flip) { | |
1907 | flags = STREAM_TOCLIENT; | |
1908 | flip = 0; | |
1909 | } else { | |
1910 | flags = STREAM_TOSERVER; | |
1911 | flip = 1; | |
1912 | } | |
1913 | ||
1914 | if (start--) { | |
1915 | flags |= STREAM_START; | |
1916 | } | |
1917 | ||
1918 | (void)AppLayerParserParse(NULL, alp_tctx, f, alproto, flags, | |
1919 | buffer, size); | |
1920 | ||
1921 | fclose(fp); | |
1922 | cnt++; | |
1923 | ||
1924 | snprintf(filename, sizeof(filename), "dump/%s.%u", fileprefix, cnt); | |
1925 | } | |
1926 | ||
077ac816 | 1927 | result = 0; |
31daf435 | 1928 | |
077ac816 VJ |
1929 | end: |
1930 | if (alp_tctx != NULL) | |
1931 | AppLayerParserThreadCtxFree(alp_tctx); | |
1932 | if (f != NULL) { | |
1933 | FlowFree(f); | |
1934 | } | |
1935 | return result; | |
1936 | } | |
31daf435 | 1937 | |
45d87d66 | 1938 | #endif /* AFLFUZZ_APPLAYER */ |
7c31a232 | 1939 | |
429c6388 | 1940 | /***** Unittests *****/ |
7c31a232 | 1941 | |
c1e485cc GS |
1942 | #ifdef UNITTESTS |
1943 | ||
429c6388 AS |
1944 | static AppLayerParserCtx alp_ctx_backup_unittest; |
1945 | ||
c1e485cc GS |
1946 | typedef struct TestState_ { |
1947 | uint8_t test; | |
429c6388 | 1948 | } TestState; |
c1e485cc GS |
1949 | |
1950 | /** | |
1951 | * \brief Test parser function to test the memory deallocation of app layer | |
1952 | * parser of occurence of an error. | |
1953 | */ | |
9634e60e | 1954 | static int TestProtocolParser(Flow *f, void *test_state, AppLayerParserState *pstate, |
9a6aef45 | 1955 | uint8_t *input, uint32_t input_len, |
7bc3c3ac | 1956 | void *local_data, const uint8_t flags) |
c1e485cc | 1957 | { |
429c6388 AS |
1958 | SCEnter(); |
1959 | SCReturnInt(-1); | |
c1e485cc GS |
1960 | } |
1961 | ||
1962 | /** \brief Function to allocates the Test protocol state memory | |
1963 | */ | |
1964 | static void *TestProtocolStateAlloc(void) | |
1965 | { | |
429c6388 | 1966 | SCEnter(); |
25a3a5c6 | 1967 | void *s = SCMalloc(sizeof(TestState)); |
e176be6f | 1968 | if (unlikely(s == NULL)) |
429c6388 | 1969 | goto end; |
c1e485cc | 1970 | memset(s, 0, sizeof(TestState)); |
429c6388 AS |
1971 | end: |
1972 | SCReturnPtr(s, "TestState"); | |
c1e485cc GS |
1973 | } |
1974 | ||
1975 | /** \brief Function to free the Test Protocol state memory | |
1976 | */ | |
1977 | static void TestProtocolStateFree(void *s) | |
1978 | { | |
25a3a5c6 | 1979 | SCFree(s); |
c1e485cc GS |
1980 | } |
1981 | ||
8bc1e120 VJ |
1982 | static uint64_t TestProtocolGetTxCnt(void *state) |
1983 | { | |
1984 | /* single tx */ | |
1985 | return 1; | |
1986 | } | |
1987 | ||
5cdeadb3 | 1988 | void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, |
429c6388 | 1989 | void (*RegisterUnittests)(void)) |
6cb00142 | 1990 | { |
429c6388 AS |
1991 | SCEnter(); |
1992 | alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. | |
1993 | RegisterUnittests = RegisterUnittests; | |
1994 | SCReturn; | |
6cb00142 AS |
1995 | } |
1996 | ||
429c6388 | 1997 | void AppLayerParserBackupParserTable(void) |
6cb00142 | 1998 | { |
429c6388 AS |
1999 | SCEnter(); |
2000 | alp_ctx_backup_unittest = alp_ctx; | |
2001 | memset(&alp_ctx, 0, sizeof(alp_ctx)); | |
2002 | SCReturn; | |
2003 | } | |
6cb00142 | 2004 | |
429c6388 AS |
2005 | void AppLayerParserRestoreParserTable(void) |
2006 | { | |
2007 | SCEnter(); | |
2008 | alp_ctx = alp_ctx_backup_unittest; | |
2009 | memset(&alp_ctx_backup_unittest, 0, sizeof(alp_ctx_backup_unittest)); | |
2010 | SCReturn; | |
6cb00142 AS |
2011 | } |
2012 | ||
2013 | /** | |
2014 | * \test Test the deallocation of app layer parser memory on occurance of | |
2015 | * error in the parsing process. | |
c1e485cc | 2016 | */ |
429c6388 | 2017 | static int AppLayerParserTest01(void) |
c1e485cc | 2018 | { |
429c6388 AS |
2019 | AppLayerParserBackupParserTable(); |
2020 | ||
9f95ab74 | 2021 | int result = 0; |
262a7300 | 2022 | Flow *f = NULL; |
c1e485cc GS |
2023 | uint8_t testbuf[] = { 0x11 }; |
2024 | uint32_t testlen = sizeof(testbuf); | |
2025 | TcpSession ssn; | |
8dbf7a0d | 2026 | AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); |
c1e485cc | 2027 | |
c1e485cc | 2028 | memset(&ssn, 0, sizeof(ssn)); |
c1e485cc GS |
2029 | |
2030 | /* Register the Test protocol state and parser functions */ | |
429c6388 AS |
2031 | AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEST, STREAM_TOSERVER, |
2032 | TestProtocolParser); | |
2033 | AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_TEST, | |
2034 | TestProtocolStateAlloc, TestProtocolStateFree); | |
8bc1e120 | 2035 | AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TEST, TestProtocolGetTxCnt); |
c1e485cc | 2036 | |
262a7300 VJ |
2037 | f = UTHBuildFlow(AF_INET, "1.2.3.4", "4.3.2.1", 20, 40); |
2038 | if (f == NULL) | |
2039 | goto end; | |
2040 | f->protoctx = &ssn; | |
262a7300 VJ |
2041 | f->alproto = ALPROTO_TEST; |
2042 | f->proto = IPPROTO_TCP; | |
c1e485cc | 2043 | |
6a53ab9c | 2044 | StreamTcpInitConfig(TRUE); |
6a53ab9c | 2045 | |
6530c3d0 | 2046 | FLOWLOCK_WRLOCK(f); |
675fa564 GL |
2047 | int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_TEST, |
2048 | STREAM_TOSERVER | STREAM_EOF, testbuf, | |
2049 | testlen); | |
c1e485cc | 2050 | if (r != -1) { |
9f95ab74 | 2051 | printf("returned %" PRId32 ", expected -1: ", r); |
6530c3d0 | 2052 | FLOWLOCK_UNLOCK(f); |
c1e485cc GS |
2053 | goto end; |
2054 | } | |
6530c3d0 | 2055 | FLOWLOCK_UNLOCK(f); |
c1e485cc | 2056 | |
c1558f5a | 2057 | if (!(ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) { |
9f95ab74 | 2058 | printf("flag should have been set, but is not: "); |
c1e485cc GS |
2059 | goto end; |
2060 | } | |
2061 | ||
9f95ab74 | 2062 | result = 1; |
429c6388 AS |
2063 | end: |
2064 | AppLayerParserRestoreParserTable(); | |
8cc525c9 | 2065 | StreamTcpFreeConfig(TRUE); |
262a7300 VJ |
2066 | |
2067 | UTHFreeFlow(f); | |
8cc525c9 PR |
2068 | return result; |
2069 | } | |
2070 | ||
6cb00142 AS |
2071 | /** |
2072 | * \test Test the deallocation of app layer parser memory on occurance of | |
2073 | * error in the parsing process for UDP. | |
8cc525c9 | 2074 | */ |
429c6388 | 2075 | static int AppLayerParserTest02(void) |
8cc525c9 | 2076 | { |
429c6388 AS |
2077 | AppLayerParserBackupParserTable(); |
2078 | ||
8cc525c9 | 2079 | int result = 1; |
262a7300 | 2080 | Flow *f = NULL; |
8cc525c9 PR |
2081 | uint8_t testbuf[] = { 0x11 }; |
2082 | uint32_t testlen = sizeof(testbuf); | |
8dbf7a0d | 2083 | AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); |
8cc525c9 PR |
2084 | |
2085 | /* Register the Test protocol state and parser functions */ | |
429c6388 AS |
2086 | AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_TEST, STREAM_TOSERVER, |
2087 | TestProtocolParser); | |
2088 | AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_TEST, | |
2089 | TestProtocolStateAlloc, TestProtocolStateFree); | |
8bc1e120 | 2090 | AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_TEST, TestProtocolGetTxCnt); |
8cc525c9 | 2091 | |
262a7300 VJ |
2092 | f = UTHBuildFlow(AF_INET, "1.2.3.4", "4.3.2.1", 20, 40); |
2093 | if (f == NULL) | |
2094 | goto end; | |
2095 | f->alproto = ALPROTO_TEST; | |
2096 | f->proto = IPPROTO_UDP; | |
a77b9b36 | 2097 | f->protomap = FlowGetProtoMapping(f->proto); |
8cc525c9 PR |
2098 | |
2099 | StreamTcpInitConfig(TRUE); | |
8cc525c9 | 2100 | |
6530c3d0 | 2101 | FLOWLOCK_WRLOCK(f); |
675fa564 GL |
2102 | int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_TEST, |
2103 | STREAM_TOSERVER | STREAM_EOF, testbuf, | |
2104 | testlen); | |
8cc525c9 PR |
2105 | if (r != -1) { |
2106 | printf("returned %" PRId32 ", expected -1: \n", r); | |
2107 | result = 0; | |
6530c3d0 | 2108 | FLOWLOCK_UNLOCK(f); |
8cc525c9 PR |
2109 | goto end; |
2110 | } | |
6530c3d0 | 2111 | FLOWLOCK_UNLOCK(f); |
8cc525c9 | 2112 | |
429c6388 AS |
2113 | end: |
2114 | AppLayerParserRestoreParserTable(); | |
6a53ab9c | 2115 | StreamTcpFreeConfig(TRUE); |
262a7300 | 2116 | UTHFreeFlow(f); |
c1e485cc GS |
2117 | return result; |
2118 | } | |
2119 | ||
7c31a232 | 2120 | |
429c6388 | 2121 | void AppLayerParserRegisterUnittests(void) |
7c31a232 | 2122 | { |
429c6388 | 2123 | SCEnter(); |
9faa4b74 | 2124 | |
429c6388 | 2125 | int ip; |
f5f14880 | 2126 | AppProto alproto; |
c23742a0 | 2127 | AppLayerParserProtoCtx *ctx; |
9faa4b74 | 2128 | |
429c6388 AS |
2129 | for (ip = 0; ip < FLOW_PROTO_DEFAULT; ip++) { |
2130 | for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { | |
2131 | ctx = &alp_ctx.ctxs[ip][alproto]; | |
2132 | if (ctx->RegisterUnittests == NULL) | |
2133 | continue; | |
2134 | ctx->RegisterUnittests(); | |
9faa4b74 VJ |
2135 | } |
2136 | } | |
2137 | ||
796dd522 JI |
2138 | UtRegisterTest("AppLayerParserTest01", AppLayerParserTest01); |
2139 | UtRegisterTest("AppLayerParserTest02", AppLayerParserTest02); | |
7c31a232 | 2140 | |
429c6388 | 2141 | SCReturn; |
c1e485cc | 2142 | } |
429c6388 AS |
2143 | |
2144 | #endif |