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