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