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