• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 22573114576

02 Mar 2026 11:03AM UTC coverage: 76.637% (+3.0%) from 73.687%
22573114576

Pull #14929

github

web-flow
Merge b9772fea4 into 90823fa90
Pull Request #14929: detect: anchor all PARSE_REGEX to reject leading/trailing content

7 of 7 new or added lines in 7 files covered. (100.0%)

12616 existing lines in 287 files now uncovered.

244546 of 319098 relevant lines covered (76.64%)

3375792.63 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.22
/src/app-layer-parser.c
1
/* Copyright (C) 2007-2026 Open Information Security Foundation
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
 */
25

26
#include "suricata-common.h"
27
#include "app-layer-parser.h"
28

29
#include "flow.h"
30
#include "flow-private.h"
31
#include "flow-util.h"
32

33
#include "app-layer-frames.h"
34
#include "app-layer-events.h"
35

36
#include "stream-tcp.h"
37

38
#include "util-validate.h"
39
#include "util-config.h"
40

41
#include "app-layer.h"
42
#include "app-layer-detect-proto.h"
43

44
#include "app-layer-ftp.h"
45
#include "app-layer-smtp.h"
46

47
#include "app-layer-smb.h"
48
#include "app-layer-htp.h"
49
#include "app-layer-ssl.h"
50
#include "app-layer-ssh.h"
51
#include "app-layer-modbus.h"
52
#include "app-layer-dnp3.h"
53
#include "app-layer-nfs-tcp.h"
54
#include "app-layer-nfs-udp.h"
55
#include "app-layer-tftp.h"
56
#include "app-layer-ike.h"
57
#include "app-layer-http2.h"
58
#include "app-layer-imap.h"
59

60
struct AppLayerParserThreadCtx_ {
61
    void *(*alproto_local_storage)[FLOW_PROTO_MAX];
62
};
63

64

65
/**
66
 * \brief App layer protocol parser context.
67
 */
68
typedef struct AppLayerParserProtoCtx_
69
{
70
    /* 0 - to_server, 1 - to_client. */
71
    AppLayerParserFPtr Parser[2];
72

73
    bool logger;
74

75
    /* Indicates the direction the parser is ready to see the data
76
     * the first time for a flow.  Values accepted -
77
     * STREAM_TOSERVER, STREAM_TOCLIENT */
78
    uint8_t first_data_dir;
79

80
    uint32_t logger_bits;   /**< registered loggers for this proto */
81

82
    void *(*StateAlloc)(void *, AppProto);
83
    void (*StateFree)(void *);
84
    void (*StateTransactionFree)(void *, uint64_t);
85
    void *(*LocalStorageAlloc)(void);
86
    void (*LocalStorageFree)(void *);
87

88
    /** get FileContainer reference from the TX. MUST return a non-NULL reference if the TX
89
     *  has or may have files in the requested direction at some point. */
90
    AppLayerGetFileState (*GetTxFiles)(void *, uint8_t);
91

92
    int (*StateGetProgress)(void *alstate, uint8_t direction);
93
    uint64_t (*StateGetTxCnt)(void *alstate);
94
    void *(*StateGetTx)(void *alstate, uint64_t tx_id);
95
    AppLayerGetTxIteratorFunc StateGetTxIterator;
96
    int complete_ts;
97
    int complete_tc;
98
    int (*StateGetEventInfoById)(
99
            uint8_t event_id, const char **event_name, AppLayerEventType *event_type);
100
    int (*StateGetEventInfo)(
101
            const char *event_name, uint8_t *event_id, AppLayerEventType *event_type);
102

103
    AppLayerStateData *(*GetStateData)(void *state);
104
    AppLayerTxData *(*GetTxData)(void *tx);
105
    void (*ApplyTxConfig)(void *state, void *tx, int mode, AppLayerTxConfig);
106

107
    void (*SetStreamDepthFlag)(void *tx, uint8_t flags);
108

109
    AppLayerParserGetFrameIdByNameFn GetFrameIdByName;
110
    AppLayerParserGetFrameNameByIdFn GetFrameNameById;
111

112
    AppLayerParserGetStateIdByNameFn GetStateIdByName;
113
    AppLayerParserGetStateNameByIdFn GetStateNameById;
114

115
    /* each app-layer has its own value */
116
    uint32_t stream_depth;
117

118
    /* Option flags such as supporting gaps or not. */
119
    uint32_t option_flags;
120
    /* coccinelle: AppLayerParserProtoCtx:option_flags:APP_LAYER_PARSER_OPT_ */
121

122
    uint32_t internal_flags;
123
    /* coccinelle: AppLayerParserProtoCtx:internal_flags:APP_LAYER_PARSER_INT_ */
124

125
#ifdef UNITTESTS
126
    void (*RegisterUnittests)(void);
127
#endif
128
} AppLayerParserProtoCtx;
129

130
typedef struct AppLayerParserCtx_ {
131
    AppLayerParserProtoCtx (*ctxs)[FLOW_PROTO_MAX];
132
    size_t ctxs_len;
133
} AppLayerParserCtx;
134

135
struct AppLayerParserState_ {
136
    /* coccinelle: AppLayerParserState:flags:APP_LAYER_PARSER_ */
137
    uint16_t flags;
138

139
    /* Indicates the current transaction that is being inspected.
140
     * We have a var per direction. */
141
    uint64_t inspect_id[2];
142
    /* Indicates the current transaction being logged.  Unlike inspect_id,
143
     * we don't need a var per direction since we don't log a transaction
144
     * unless we have the entire transaction. */
145
    uint64_t log_id;
146

147
    uint64_t min_id;
148

149
    /* Used to store decoder events. */
150
    AppLayerDecoderEvents *decoder_events;
151

152
    FramesContainer *frames;
153
};
154

155
enum ExceptionPolicy g_applayerparser_error_policy = EXCEPTION_POLICY_NOT_SET;
156

157
static void AppLayerConfig(void)
158
{
44✔
159
    g_applayerparser_error_policy = ExceptionPolicyParse("app-layer.error-policy", true);
44✔
160
}
44✔
161

162
enum ExceptionPolicy AppLayerErrorGetExceptionPolicy(void)
163
{
442✔
164
    return g_applayerparser_error_policy;
442✔
165
}
442✔
166

167
static void AppLayerParserFramesFreeContainer(FramesContainer *frames)
168
{
39,339✔
169
    if (frames != NULL) {
39,339✔
170
        FramesFree(&frames->toserver);
27,609✔
171
        FramesFree(&frames->toclient);
27,609✔
172
        SCFree(frames);
27,609✔
173
    }
27,609✔
174
}
39,339✔
175

176
void AppLayerFramesFreeContainer(Flow *f)
177
{
1,856✔
178
    if (f == NULL || f->alparser == NULL || f->alparser->frames == NULL)
1,856✔
179
        return;
×
180
    AppLayerParserFramesFreeContainer(f->alparser->frames);
1,856✔
181
    f->alparser->frames = NULL;
1,856✔
182
}
1,856✔
183

184
FramesContainer *AppLayerFramesGetContainer(const Flow *f)
185
{
3,529,037✔
186
    if (f == NULL || f->alparser == NULL)
3,529,092✔
187
        return NULL;
166,262✔
188
    return f->alparser->frames;
3,362,775✔
189
}
3,529,037✔
190

191
FramesContainer *AppLayerFramesSetupContainer(Flow *f)
192
{
1,245,388✔
193
#ifdef UNITTESTS
194
    if (f == NULL || f->alparser == NULL || (f->proto == IPPROTO_TCP && f->protoctx == NULL))
195
        return NULL;
196
#endif
197
    DEBUG_VALIDATE_BUG_ON(f == NULL || f->alparser == NULL);
1,245,388✔
198
    if (f->alparser->frames == NULL) {
1,245,388✔
199
        f->alparser->frames = SCCalloc(1, sizeof(FramesContainer));
27,609✔
200
        if (f->alparser->frames == NULL) {
27,609✔
201
            return NULL;
×
202
        }
×
203
#ifdef DEBUG
204
        f->alparser->frames->toserver.ipproto = f->proto;
205
        f->alparser->frames->toserver.alproto = f->alproto;
206
        f->alparser->frames->toclient.ipproto = f->proto;
207
        f->alparser->frames->toclient.alproto = f->alproto;
208
#endif
209
    }
27,609✔
210
    return f->alparser->frames;
1,245,388✔
211
}
1,245,388✔
212

213
#ifdef UNITTESTS
214
void UTHAppLayerParserStateGetIds(void *ptr, uint64_t *i1, uint64_t *i2, uint64_t *log, uint64_t *min)
215
{
9✔
216
    struct AppLayerParserState_ *s = ptr;
9✔
217
    *i1 = s->inspect_id[0];
9✔
218
    *i2 = s->inspect_id[1];
9✔
219
    *log = s->log_id;
9✔
220
    *min = s->min_id;
9✔
221
}
9✔
222
#endif
223

224
/* Static global version of the parser context.
225
 * Post 2.0 let's look at changing this to move it out to app-layer.c. */
226
static AppLayerParserCtx alp_ctx;
227

228
int AppLayerParserProtoIsRegistered(uint8_t ipproto, AppProto alproto)
229
{
338,322✔
230
    uint8_t ipproto_map = FlowGetProtoMapping(ipproto);
338,322✔
231

232
    return (alp_ctx.ctxs[alproto][ipproto_map].StateAlloc != NULL) ? 1 : 0;
338,322✔
233
}
338,322✔
234

235
AppLayerParserState *AppLayerParserStateAlloc(void)
236
{
37,477✔
237
    SCEnter();
37,477✔
238

239
    AppLayerParserState *pstate = (AppLayerParserState *)SCCalloc(1, sizeof(*pstate));
37,477✔
240
    if (pstate == NULL)
37,477✔
241
        goto end;
×
242

243
 end:
37,477✔
244
    SCReturnPtr(pstate, "AppLayerParserState");
37,472✔
245
}
37,477✔
246

247
void AppLayerParserStateFree(AppLayerParserState *pstate)
248
{
37,483✔
249
    SCEnter();
37,483✔
250

251
    if (pstate->decoder_events != NULL)
37,483✔
252
        SCAppLayerDecoderEventsFreeEvents(&pstate->decoder_events);
×
253
    AppLayerParserFramesFreeContainer(pstate->frames);
37,483✔
254
    SCFree(pstate);
37,483✔
255

256
    SCReturn;
37,483✔
257
}
37,483✔
258

259
int AppLayerParserSetup(void)
260
{
44✔
261
    SCEnter();
44✔
262
    // initial allocation that will later be grown using realloc,
263
    // when new protocols register themselves and make g_alproto_max grow
264
    alp_ctx.ctxs = SCCalloc(g_alproto_max, sizeof(AppLayerParserProtoCtx[FLOW_PROTO_MAX]));
44✔
265
    if (unlikely(alp_ctx.ctxs == NULL)) {
44✔
266
        FatalError("Unable to alloc alp_ctx.ctxs.");
×
267
    }
×
268
    alp_ctx.ctxs_len = g_alproto_max;
44✔
269
    SCReturnInt(0);
44✔
270
}
44✔
271

272
void AppLayerParserPostStreamSetup(void)
273
{
1,425✔
274
    /* lets set a default value for stream_depth */
275
    for (int flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) {
5,700✔
276
        for (AppProto alproto = 0; alproto < g_alproto_max; alproto++) {
175,275✔
277
            if (!(alp_ctx.ctxs[alproto][flow_proto].internal_flags &
171,000✔
278
                        APP_LAYER_PARSER_INT_STREAM_DEPTH_SET)) {
171,000✔
279
                alp_ctx.ctxs[alproto][flow_proto].stream_depth = stream_config.reassembly_depth;
168,178✔
280
            }
168,178✔
281
        }
171,000✔
282
    }
4,275✔
283
}
1,425✔
284

285
int AppLayerParserDeSetup(void)
286
{
30✔
287
    SCEnter();
30✔
288

289
    SCFree(alp_ctx.ctxs);
30✔
290

291
    FTPParserCleanup();
30✔
292
    SMTPParserCleanup();
30✔
293

294
    SCReturnInt(0);
30✔
295
}
30✔
296

297
AppLayerParserThreadCtx *AppLayerParserThreadCtxAlloc(void)
298
{
13,484✔
299
    SCEnter();
13,484✔
300

301
    AppLayerParserThreadCtx *tctx = SCCalloc(1, sizeof(*tctx));
13,484✔
302
    if (tctx == NULL)
13,484✔
303
        goto end;
×
304

305
    tctx->alproto_local_storage = SCCalloc(g_alproto_max, sizeof(void *[FLOW_PROTO_MAX]));
13,484✔
306
    if (unlikely(tctx->alproto_local_storage == NULL)) {
13,484✔
307
        SCFree(tctx);
×
308
        tctx = NULL;
×
309
        goto end;
×
310
    }
×
311
    for (uint8_t flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) {
53,936✔
312
        for (AppProto alproto = 0; alproto < g_alproto_max; alproto++) {
1,658,532✔
313
            uint8_t ipproto = FlowGetReverseProtoMapping(flow_proto);
1,618,080✔
314

315
            tctx->alproto_local_storage[alproto][flow_proto] =
1,618,080✔
316
                    AppLayerParserGetProtocolParserLocalStorage(ipproto, alproto);
1,618,080✔
317
        }
1,618,080✔
318
    }
40,452✔
319

320
 end:
13,484✔
321
    SCReturnPtr(tctx, "void *");
13,484✔
322
}
13,484✔
323

324
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
325
{
13,480✔
326
    SCEnter();
13,480✔
327

328
    for (uint8_t flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) {
53,920✔
329
        for (AppProto alproto = 0; alproto < g_alproto_max; alproto++) {
1,658,040✔
330
            uint8_t ipproto = FlowGetReverseProtoMapping(flow_proto);
1,617,600✔
331

332
            AppLayerParserDestroyProtocolParserLocalStorage(
1,617,600✔
333
                    ipproto, alproto, tctx->alproto_local_storage[alproto][flow_proto]);
1,617,600✔
334
        }
1,617,600✔
335
    }
40,440✔
336

337
    SCFree(tctx->alproto_local_storage);
13,480✔
338
    SCFree(tctx);
13,480✔
339
    SCReturn;
13,480✔
340
}
13,480✔
341

342
/** \brief check if a parser is enabled in the config
343
 *  Returns enabled always if: were running unittests
344
 */
345
int SCAppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name)
346
{
1,734✔
347
    SCEnter();
1,734✔
348

349
    int enabled = 1;
1,734✔
350
    char param[100];
1,734✔
351
    SCConfNode *node;
1,734✔
352
    int r;
1,734✔
353

354
    if (RunmodeIsUnittests())
1,734✔
355
        goto enabled;
89✔
356

357
    r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.",
1,645✔
358
                 alproto_name, ".enabled");
1,645✔
359
    if (r < 0) {
1,645✔
360
        FatalError("snprintf failure.");
×
361
    } else if (r > (int)sizeof(param)) {
1,645✔
362
        FatalError("buffer not big enough to write param.");
×
363
    }
×
364

365
    node = SCConfGetNode(param);
1,645✔
366
    if (node == NULL) {
1,645✔
367
        SCLogDebug("Entry for %s not found.", param);
1,365✔
368
        r = snprintf(param, sizeof(param), "%s%s%s%s%s", "app-layer.protocols.",
1,365✔
369
                     alproto_name, ".", ipproto, ".enabled");
1,365✔
370
        if (r < 0) {
1,365✔
371
            FatalError("snprintf failure.");
×
372
        } else if (r > (int)sizeof(param)) {
1,365✔
373
            FatalError("buffer not big enough to write param.");
×
374
        }
×
375

376
        node = SCConfGetNode(param);
1,365✔
377
        if (node == NULL) {
1,365✔
378
            SCLogDebug("Entry for %s not found.", param);
1,329✔
379
            goto enabled;
1,329✔
380
        }
1,329✔
381
    }
1,365✔
382

383
    if (SCConfValIsTrue(node->val)) {
316✔
384
        goto enabled;
316✔
385
    } else if (SCConfValIsFalse(node->val)) {
316✔
386
        goto disabled;
×
UNCOV
387
    } else if (strcasecmp(node->val, "detection-only") == 0) {
×
UNCOV
388
        goto disabled;
×
UNCOV
389
    } else {
×
390
        SCLogError("Invalid value found for %s.", param);
×
391
        exit(EXIT_FAILURE);
×
392
    }
×
393

UNCOV
394
 disabled:
×
UNCOV
395
    enabled = 0;
×
396
 enabled:
1,734✔
397
    SCReturnInt(enabled);
1,734✔
UNCOV
398
}
×
399

400
/***** Parser related registration *****/
401

402
int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto,
403
                      uint8_t direction,
404
                      AppLayerParserFPtr Parser)
405
{
3,398✔
406
    SCEnter();
3,398✔
407

408
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)]
3,398✔
409
            .Parser[(direction & STREAM_TOSERVER) ? 0 : 1] = Parser;
3,398✔
410

411
    SCReturnInt(0);
3,398✔
412
}
3,398✔
413

414
void SCAppLayerParserRegisterParserAcceptableDataDirection(
415
        uint8_t ipproto, AppProto alproto, uint8_t direction)
416
{
246✔
417
    SCEnter();
246✔
418

419
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].first_data_dir |=
246✔
420
            (direction & (STREAM_TOSERVER | STREAM_TOCLIENT));
246✔
421

422
    SCReturn;
246✔
423
}
246✔
424

425
void AppLayerParserRegisterOptionFlags(uint8_t ipproto, AppProto alproto,
426
        uint32_t flags)
427
{
424✔
428
    SCEnter();
424✔
429

430
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].option_flags |= flags;
424✔
431

432
    SCReturn;
424✔
433
}
424✔
434

435
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto,
436
        void *(*StateAlloc)(void *, AppProto), void (*StateFree)(void *))
437
{
1,699✔
438
    SCEnter();
1,699✔
439

440
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateAlloc = StateAlloc;
1,699✔
441
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateFree = StateFree;
1,699✔
442

443
    SCReturn;
1,699✔
444
}
1,699✔
445

446
void AppLayerParserRegisterLocalStorageFunc(uint8_t ipproto, AppProto alproto,
447
                                 void *(*LocalStorageAlloc)(void),
448
                                 void (*LocalStorageFree)(void *))
449
{
88✔
450
    SCEnter();
88✔
451

452
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].LocalStorageAlloc = LocalStorageAlloc;
88✔
453
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].LocalStorageFree = LocalStorageFree;
88✔
454

455
    SCReturn;
88✔
456
}
88✔
457

458
void AppLayerParserRegisterGetTxFilesFunc(
459
        uint8_t ipproto, AppProto alproto, AppLayerGetFileState (*GetTxFiles)(void *, uint8_t))
460
{
352✔
461
    SCEnter();
352✔
462

463
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetTxFiles = GetTxFiles;
352✔
464

465
    SCReturn;
352✔
466
}
352✔
467

468
void AppLayerParserRegisterLoggerBits(uint8_t ipproto, AppProto alproto, LoggerId bits)
469
{
78,396✔
470
    SCEnter();
78,396✔
471

472
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].logger_bits = bits;
78,396✔
473

474
    SCReturn;
78,396✔
475
}
78,396✔
476

477
void SCAppLayerParserRegisterLogger(uint8_t ipproto, AppProto alproto)
478
{
24,701✔
479
    SCEnter();
24,701✔
480

481
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].logger = true;
24,701✔
482

483
    SCReturn;
24,701✔
484
}
24,701✔
485

486
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto,
487
    int (*StateGetProgress)(void *alstate, uint8_t direction))
488
{
1,699✔
489
    SCEnter();
1,699✔
490

491
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetProgress = StateGetProgress;
1,699✔
492

493
    SCReturn;
1,699✔
494
}
1,699✔
495

496
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto,
497
                           void (*StateTransactionFree)(void *, uint64_t))
498
{
1,699✔
499
    SCEnter();
1,699✔
500

501
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateTransactionFree = StateTransactionFree;
1,699✔
502

503
    SCReturn;
1,699✔
504
}
1,699✔
505

506
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto,
507
                         uint64_t (*StateGetTxCnt)(void *alstate))
508
{
1,699✔
509
    SCEnter();
1,699✔
510

511
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetTxCnt = StateGetTxCnt;
1,699✔
512

513
    SCReturn;
1,699✔
514
}
1,699✔
515

516
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto,
517
                      void *(StateGetTx)(void *alstate, uint64_t tx_id))
518
{
1,699✔
519
    SCEnter();
1,699✔
520

521
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetTx = StateGetTx;
1,699✔
522

523
    SCReturn;
1,699✔
524
}
1,699✔
525

526
void AppLayerParserRegisterGetTxIterator(uint8_t ipproto, AppProto alproto,
527
                      AppLayerGetTxIteratorFunc Func)
528
{
1,523✔
529
    SCEnter();
1,523✔
530
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetTxIterator = Func;
1,523✔
531
    SCReturn;
1,523✔
532
}
1,523✔
533

534
void AppLayerParserRegisterStateProgressCompletionStatus(
535
        AppProto alproto, const int ts, const int tc)
536
{
1,699✔
537
    BUG_ON(ts == 0);
1,699✔
538
    BUG_ON(tc == 0);
1,699✔
539
    BUG_ON(!AppProtoIsValid(alproto));
1,699✔
540
    BUG_ON(alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_ts != 0 &&
1,699✔
541
            alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_ts != ts);
1,699✔
542
    BUG_ON(alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_tc != 0 &&
1,699✔
543
            alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_tc != tc);
1,699✔
544

545
    alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_ts = ts;
1,699✔
546
    alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_tc = tc;
1,699✔
547
}
1,699✔
548

549
void AppLayerParserRegisterGetEventInfoById(uint8_t ipproto, AppProto alproto,
550
        int (*StateGetEventInfoById)(
551
                uint8_t event_id, const char **event_name, AppLayerEventType *event_type))
552
{
1,479✔
553
    SCEnter();
1,479✔
554

555
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetEventInfoById =
1,479✔
556
            StateGetEventInfoById;
1,479✔
557

558
    SCReturn;
1,479✔
559
}
1,479✔
560

561
void AppLayerParserRegisterGetStateFuncs(uint8_t ipproto, AppProto alproto,
562
        AppLayerParserGetStateIdByNameFn GetIdByNameFunc,
563
        AppLayerParserGetStateNameByIdFn GetNameByIdFunc)
564
{
132✔
565
    SCEnter();
132✔
566
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetStateIdByName = GetIdByNameFunc;
132✔
567
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetStateNameById = GetNameByIdFunc;
132✔
568
    SCReturn;
132✔
569
}
132✔
570

571
void AppLayerParserRegisterGetFrameFuncs(uint8_t ipproto, AppProto alproto,
572
        AppLayerParserGetFrameIdByNameFn GetIdByNameFunc,
573
        AppLayerParserGetFrameNameByIdFn GetNameByIdFunc)
574
{
994✔
575
    SCEnter();
994✔
576
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetFrameIdByName = GetIdByNameFunc;
994✔
577
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetFrameNameById = GetNameByIdFunc;
994✔
578
    SCReturn;
994✔
579
}
994✔
580

581
void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto,
582
        int (*StateGetEventInfo)(
583
                const char *event_name, uint8_t *event_id, AppLayerEventType *event_type))
584
{
1,523✔
585
    SCEnter();
1,523✔
586

587
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetEventInfo = StateGetEventInfo;
1,523✔
588

589
    SCReturn;
1,523✔
590
}
1,523✔
591

592
void AppLayerParserRegisterTxDataFunc(uint8_t ipproto, AppProto alproto,
593
        AppLayerTxData *(*GetTxData)(void *tx))
594
{
1,699✔
595
    SCEnter();
1,699✔
596

597
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetTxData = GetTxData;
1,699✔
598

599
    SCReturn;
1,699✔
600
}
1,699✔
601

602
void AppLayerParserRegisterStateDataFunc(
603
        uint8_t ipproto, AppProto alproto, AppLayerStateData *(*GetStateData)(void *state))
604
{
1,699✔
605
    SCEnter();
1,699✔
606

607
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetStateData = GetStateData;
1,699✔
608

609
    SCReturn;
1,699✔
610
}
1,699✔
611

612
void AppLayerParserRegisterApplyTxConfigFunc(uint8_t ipproto, AppProto alproto,
613
        void (*ApplyTxConfig)(void *state, void *tx, int mode, AppLayerTxConfig))
614
{
88✔
615
    SCEnter();
88✔
616

617
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].ApplyTxConfig = ApplyTxConfig;
88✔
618

619
    SCReturn;
88✔
620
}
88✔
621

622
void AppLayerParserRegisterSetStreamDepthFlag(uint8_t ipproto, AppProto alproto,
623
        void (*SetStreamDepthFlag)(void *tx, uint8_t flags))
624
{
44✔
625
    SCEnter();
44✔
626

627
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].SetStreamDepthFlag = SetStreamDepthFlag;
44✔
628

629
    SCReturn;
44✔
630
}
44✔
631

632
/***** Get and transaction functions *****/
633

634
void *AppLayerParserGetProtocolParserLocalStorage(uint8_t ipproto, AppProto alproto)
635
{
1,618,080✔
636
    SCEnter();
1,618,080✔
637
    void * r = NULL;
1,618,080✔
638

639
    if (alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].LocalStorageAlloc != NULL) {
1,618,080✔
640
        r = alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].LocalStorageAlloc();
26,968✔
641
    }
26,968✔
642

643
    SCReturnPtr(r, "void *");
1,618,080✔
644
}
1,618,080✔
645

646
void AppLayerParserDestroyProtocolParserLocalStorage(uint8_t ipproto, AppProto alproto,
647
                                          void *local_data)
648
{
1,617,600✔
649
    SCEnter();
1,617,600✔
650

651
    if (alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].LocalStorageFree != NULL) {
1,617,600✔
652
        alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].LocalStorageFree(local_data);
26,960✔
653
    }
26,960✔
654

655
    SCReturn;
1,617,600✔
656
}
1,617,600✔
657

658
/** \brief default tx iterator
659
 *
660
 *  Used if the app layer parser doesn't register its own iterator.
661
 *  Simply walks the tx_id space until it finds a tx. Uses 'state' to
662
 *  keep track of where it left off.
663
 *
664
 *  \retval txptr or NULL if no more txs in list
665
 */
666
static AppLayerGetTxIterTuple AppLayerDefaultGetTxIterator(
667
        const uint8_t ipproto, const AppProto alproto,
668
        void *alstate, uint64_t min_tx_id, uint64_t max_tx_id,
669
        AppLayerGetTxIterState *state)
670
{
205,541✔
671
    uint64_t ustate = *(uint64_t *)state;
205,541✔
672
    uint64_t tx_id = MAX(min_tx_id, ustate);
205,541✔
673
    for ( ; tx_id < max_tx_id; tx_id++) {
205,570✔
674
        void *tx_ptr = AppLayerParserGetTx(ipproto, alproto, alstate, tx_id);
181,091✔
675
        if (tx_ptr != NULL) {
181,091✔
676
            ustate = tx_id + 1;
181,062✔
677
            *state = *(AppLayerGetTxIterState *)&ustate;
181,062✔
678
            AppLayerGetTxIterTuple tuple = {
181,062✔
679
                .tx_ptr = tx_ptr,
181,062✔
680
                .tx_id = tx_id,
181,062✔
681
                .has_next = (tx_id + 1 < max_tx_id),
181,062✔
682
            };
181,062✔
683
            SCLogDebug("tuple: %p/%"PRIu64"/%s", tuple.tx_ptr, tuple.tx_id,
181,062✔
684
                    tuple.has_next ? "true" : "false");
181,062✔
685
            return tuple;
181,062✔
686
        }
181,062✔
687
    }
181,091✔
688

689
    AppLayerGetTxIterTuple no_tuple = { NULL, 0, false };
24,479✔
690
    return no_tuple;
24,479✔
691
}
205,541✔
692

693
AppLayerGetTxIteratorFunc AppLayerGetTxIterator(const uint8_t ipproto,
694
        const AppProto alproto)
695
{
2,790,799✔
696
    AppLayerGetTxIteratorFunc Func =
2,790,799✔
697
            alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetTxIterator;
2,790,799✔
698
    return Func ? Func : AppLayerDefaultGetTxIterator;
2,790,799✔
699
}
2,790,799✔
700

701
uint64_t AppLayerParserGetTransactionLogId(AppLayerParserState *pstate)
702
{
815,513✔
703
    SCEnter();
815,513✔
704

705
    SCReturnCT((pstate == NULL) ? 0 : pstate->log_id, "uint64_t");
815,513✔
706
}
815,513✔
707

708
uint64_t AppLayerParserGetMinId(AppLayerParserState *pstate)
709
{
8,939✔
710
    SCEnter();
8,939✔
711

712
    SCReturnCT((pstate == NULL) ? 0 : pstate->min_id, "uint64_t");
8,939✔
713
}
8,939✔
714

715
void AppLayerParserSetTransactionLogId(AppLayerParserState *pstate, uint64_t tx_id)
716
{
93,599✔
717
    SCEnter();
93,599✔
718

719
    if (pstate != NULL)
93,599✔
720
        pstate->log_id = tx_id;
93,599✔
721

722
    SCReturn;
93,599✔
723
}
93,599✔
724

725
uint64_t AppLayerParserGetTransactionInspectId(AppLayerParserState *pstate, uint8_t direction)
726
{
1,193,650✔
727
    SCEnter();
1,193,650✔
728

729
    if (pstate != NULL)
1,193,650✔
730
        SCReturnCT(pstate->inspect_id[(direction & STREAM_TOSERVER) ? 0 : 1], "uint64_t");
1,193,673✔
731

732
    DEBUG_VALIDATE_BUG_ON(1);
2,147,483,647✔
733
    SCReturnCT(0ULL, "uint64_t");
2,147,483,647✔
734
}
1,193,650✔
735

736
inline uint8_t AppLayerParserGetTxDetectProgress(AppLayerTxData *txd, const uint8_t dir)
737
{
×
738
    uint8_t p = (dir & STREAM_TOSERVER) ? txd->detect_progress_ts : txd->detect_progress_tc;
×
739
    return p;
×
740
}
×
741

742
static inline uint32_t GetTxLogged(AppLayerTxData *txd)
743
{
187,136✔
744
    return txd->logged;
187,136✔
745
}
187,136✔
746

747
void SCAppLayerTxDataCleanup(AppLayerTxData *txd)
748
{
310,261✔
749
    if (txd->de_state) {
310,261✔
750
        SCDetectEngineStateFree(txd->de_state);
17,036✔
751
    }
17,036✔
752
    if (txd->events) {
310,261✔
753
        SCAppLayerDecoderEventsFreeEvents(&txd->events);
16,178✔
754
    }
16,178✔
755
    if (txd->txbits) {
310,261✔
UNCOV
756
        SCGenericVarFree(txd->txbits);
×
UNCOV
757
    }
×
758
}
310,261✔
759

760
void AppLayerParserSetTransactionInspectId(const Flow *f, AppLayerParserState *pstate,
761
                                           void *alstate, const uint8_t flags,
762
                                           bool tag_txs_as_inspected)
763
{
579,788✔
764
    SCEnter();
579,788✔
765

766
    const int direction = (flags & STREAM_TOSERVER) ? 0 : 1;
579,788✔
767
    const uint64_t total_txs = AppLayerParserGetTxCnt(f, alstate);
579,788✔
768
    uint64_t idx = AppLayerParserGetTransactionInspectId(pstate, flags);
579,788✔
769
    const int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(f->alproto, flags);
579,788✔
770
    const uint8_t ipproto = f->proto;
579,788✔
771
    const AppProto alproto = f->alproto;
579,788✔
772

773
    AppLayerGetTxIteratorFunc IterFunc = AppLayerGetTxIterator(ipproto, alproto);
579,788✔
774
    AppLayerGetTxIterState state = { 0 };
579,788✔
775

776
    SCLogDebug("called: %s, tag_txs_as_inspected %s",direction==0?"toserver":"toclient",
579,788✔
777
            tag_txs_as_inspected?"true":"false");
579,788✔
778

779
    /* mark all txs as inspected if the applayer progress is
780
     * at the 'end state'. */
781
    while (1) {
633,457✔
782
        AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, idx, total_txs, &state);
633,453✔
783
        if (ires.tx_ptr == NULL)
633,453✔
784
            break;
100,827✔
785

786
        void *tx = ires.tx_ptr;
532,626✔
787
        idx = ires.tx_id;
532,626✔
788

789
        int state_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx, flags);
532,626✔
790
        if (state_progress < state_done_progress)
532,626✔
791
            break;
390,152✔
792

793
        AppLayerTxData *txd = AppLayerParserGetTxData(ipproto, alproto, tx);
142,474✔
794
        if (tag_txs_as_inspected) {
142,474✔
795
            const uint8_t inspected_flag = (flags & STREAM_TOSERVER) ? APP_LAYER_TX_INSPECTED_TS
2,423✔
796
                                                                     : APP_LAYER_TX_INSPECTED_TC;
2,423✔
797
            if (txd->flags & inspected_flag) {
2,423✔
798
                txd->flags |= inspected_flag;
×
799
                SCLogDebug("%p/%" PRIu64 " in-order tx is done for direction %s. Flags %02x", tx,
×
800
                        idx, flags & STREAM_TOSERVER ? "toserver" : "toclient", txd->flags);
×
801
            }
×
802
        }
2,423✔
803
        idx++;
142,474✔
804
        if (!ires.has_next)
142,474✔
805
            break;
88,805✔
806
    }
142,474✔
807
    pstate->inspect_id[direction] = idx;
579,788✔
808
    SCLogDebug("inspect_id now %"PRIu64, pstate->inspect_id[direction]);
579,788✔
809

810
    /* if necessary we flag all txs that are complete as 'inspected'
811
     * also move inspect_id forward. */
812
    if (tag_txs_as_inspected) {
579,788✔
813
        /* continue at idx */
814
        while (1) {
8,971✔
815
            AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, idx, total_txs, &state);
8,971✔
816
            if (ires.tx_ptr == NULL)
8,971✔
817
                break;
6,117✔
818

819
            void *tx = ires.tx_ptr;
2,854✔
820
            /* if we got a higher id than the minimum we requested, we
821
             * skipped a bunch of 'null-txs'. Lets see if we can up the
822
             * inspect tracker */
823
            if (ires.tx_id > idx && pstate->inspect_id[direction] == idx) {
2,854✔
824
                pstate->inspect_id[direction] = ires.tx_id;
3✔
825
            }
3✔
826
            idx = ires.tx_id;
2,854✔
827

828
            const int state_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx, flags);
2,854✔
829
            if (state_progress < state_done_progress)
2,854✔
830
                break;
2,850✔
831

832
            /* txd can be NULL for HTTP sessions where the user data alloc failed */
833
            AppLayerTxData *txd = AppLayerParserGetTxData(ipproto, alproto, tx);
4✔
834
            const uint8_t inspected_flag = (flags & STREAM_TOSERVER) ? APP_LAYER_TX_INSPECTED_TS
4✔
835
                                                                     : APP_LAYER_TX_INSPECTED_TC;
4✔
836
            if (txd->flags & inspected_flag) {
4✔
837
                txd->flags |= inspected_flag;
×
838
                SCLogDebug("%p/%" PRIu64 " out of order tx is done for direction %s. Flag %02x", tx,
×
839
                        idx, flags & STREAM_TOSERVER ? "toserver" : "toclient", txd->flags);
×
840

841
                SCLogDebug("%p/%" PRIu64 " out of order tx. Update inspect_id? %" PRIu64, tx, idx,
×
842
                        pstate->inspect_id[direction]);
×
843
                if (pstate->inspect_id[direction] + 1 == idx)
×
844
                    pstate->inspect_id[direction] = idx;
×
845
            }
×
846
            if (!ires.has_next)
4✔
847
                break;
2✔
848
            idx++;
2✔
849
        }
2✔
850
    }
8,969✔
851

852
    SCReturn;
579,788✔
853
}
579,788✔
854

855
AppLayerDecoderEvents *AppLayerParserGetDecoderEvents(AppLayerParserState *pstate)
856
{
3,254,847✔
857
    SCEnter();
3,254,847✔
858

859
    SCReturnPtr(pstate->decoder_events,
3,254,847✔
860
                "AppLayerDecoderEvents *");
3,254,847✔
861
}
3,254,847✔
862

863
AppLayerDecoderEvents *AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto,
864
                                        void *tx)
865
{
2,233,147✔
866
    SCEnter();
2,233,147✔
867

868
    AppLayerDecoderEvents *ptr = NULL;
2,233,147✔
869

870
    /* Access events via the tx_data. */
871
    AppLayerTxData *txd = AppLayerParserGetTxData(ipproto, alproto, tx);
2,233,147✔
872
    if (txd->events != NULL) {
2,233,147✔
873
        ptr = txd->events;
124,868✔
874
    }
124,868✔
875

876
    SCReturnPtr(ptr, "AppLayerDecoderEvents *");
2,233,147✔
877
}
2,233,147✔
878

879
AppLayerGetFileState AppLayerParserGetTxFiles(const Flow *f, void *tx, const uint8_t direction)
880
{
990,411✔
881
    SCEnter();
990,411✔
882

883
    if (alp_ctx.ctxs[f->alproto][f->protomap].GetTxFiles != NULL) {
990,411✔
884
        return alp_ctx.ctxs[f->alproto][f->protomap].GetTxFiles(tx, direction);
973,752✔
885
    }
973,752✔
886

887
    AppLayerGetFileState files = { .fc = NULL, .cfg = NULL };
16,659✔
888
    return files;
16,659✔
889
}
990,411✔
890

891
static void AppLayerParserFileTxHousekeeping(
892
        const Flow *f, void *tx, const uint8_t pkt_dir, const bool trunc)
893
{
153,695✔
894
    AppLayerGetFileState files = AppLayerParserGetTxFiles(f, tx, pkt_dir);
153,695✔
895
    if (files.fc) {
153,696✔
896
        FilesPrune(files.fc, files.cfg, trunc);
153,696✔
897
    }
153,696✔
898
}
153,695✔
899

900
#define IS_DISRUPTED(flags) ((flags) & (STREAM_DEPTH | STREAM_GAP))
206,886,757✔
901

902
extern int g_detect_disabled;
903
extern bool g_file_logger_enabled;
904
extern bool g_filedata_logger_enabled;
905

906
/**
907
 * \brief remove obsolete (inspected and logged) transactions
908
 */
909
void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir)
910
{
832,173✔
911
    SCEnter();
832,173✔
912
    DEBUG_ASSERT_FLOW_LOCKED(f);
832,173✔
913

914
    AppLayerParserProtoCtx *p = &alp_ctx.ctxs[f->alproto][f->protomap];
832,173✔
915
    if (unlikely(p->StateTransactionFree == NULL))
832,173✔
916
        SCReturn;
16,162✔
917

918
    const bool has_tx_detect_flags = !g_detect_disabled;
816,011✔
919
    const uint8_t ipproto = f->proto;
816,011✔
920
    const AppProto alproto = f->alproto;
816,011✔
921
    void * const alstate = f->alstate;
816,011✔
922
    AppLayerParserState * const alparser = f->alparser;
816,011✔
923

924
    if (alstate == NULL || alparser == NULL)
816,035✔
925
        SCReturn;
4✔
926

927
    const uint64_t min = alparser->min_id;
816,007✔
928
    const uint64_t total_txs = AppLayerParserGetTxCnt(f, alstate);
816,007✔
929
    const LoggerId logger_expectation = AppLayerParserProtocolGetLoggerBits(ipproto, alproto);
816,007✔
930
    const int tx_end_state_ts = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOSERVER);
816,007✔
931
    const int tx_end_state_tc = AppLayerParserGetStateProgressCompletionStatus(alproto, STREAM_TOCLIENT);
816,007✔
932
    const uint8_t ts_disrupt_flags = FlowGetDisruptionFlags(f, STREAM_TOSERVER);
816,007✔
933
    const uint8_t tc_disrupt_flags = FlowGetDisruptionFlags(f, STREAM_TOCLIENT);
816,007✔
934

935
    int pkt_dir_trunc = -1;
816,007✔
936

937
    AppLayerGetTxIteratorFunc IterFunc = AppLayerGetTxIterator(ipproto, alproto);
816,007✔
938
    AppLayerGetTxIterState state;
816,007✔
939
    memset(&state, 0, sizeof(state));
816,007✔
940
    uint64_t i = min;
816,007✔
941
    uint64_t new_min = min;
816,007✔
942
    SCLogDebug("start min %"PRIu64, min);
816,007✔
943
    bool skipped = false;
816,007✔
944
    // const bool support_files = AppLayerParserSupportsFiles(f->proto, f->alproto);
945

946
    while (1) {
54,808,970✔
947
        AppLayerGetTxIterTuple ires = IterFunc(ipproto, alproto, alstate, i, total_txs, &state);
54,808,970✔
948
        if (ires.tx_ptr == NULL)
54,808,970✔
949
            break;
260,635✔
950

951
        bool tx_skipped = false;
54,808,970✔
952
        void *tx = ires.tx_ptr;
54,548,335✔
953
        i = ires.tx_id; // actual tx id for the tx the IterFunc returned
54,548,335✔
954

955
        SCLogDebug("%p/%"PRIu64" checking", tx, i);
54,548,335✔
956
        AppLayerTxData *txd = AppLayerParserGetTxData(ipproto, alproto, tx);
54,548,335✔
957
        if (AppLayerParserHasFilesInDir(txd, pkt_dir)) {
54,548,335✔
958
            if (pkt_dir_trunc == -1)
153,696✔
959
                pkt_dir_trunc = IS_DISRUPTED(
132,861✔
960
                        (pkt_dir == STREAM_TOSERVER) ? ts_disrupt_flags : tc_disrupt_flags);
153,696✔
961
            AppLayerParserFileTxHousekeeping(f, tx, pkt_dir, (bool)pkt_dir_trunc);
153,696✔
962
        }
153,696✔
963
        // should be reset by parser next time it updates the tx
964
        if (pkt_dir & STREAM_TOSERVER) {
54,548,335✔
965
            txd->updated_ts = false;
52,879,160✔
966
        } else {
52,879,176✔
967
            txd->updated_tc = false;
1,669,175✔
968
        }
1,669,175✔
969
        const int tx_progress_tc =
54,548,335✔
970
                AppLayerParserGetStateProgress(ipproto, alproto, tx, tc_disrupt_flags);
54,548,335✔
971
        if (tx_progress_tc < tx_end_state_tc) {
54,548,335✔
972
            SCLogDebug("%p/%"PRIu64" skipping: tc parser not done", tx, i);
2,300,782✔
973
            skipped = true;
2,300,782✔
974
            goto next;
2,300,782✔
975
        }
2,300,782✔
976
        const int tx_progress_ts =
52,247,553✔
977
                AppLayerParserGetStateProgress(ipproto, alproto, tx, ts_disrupt_flags);
52,247,553✔
978
        if (tx_progress_ts < tx_end_state_ts) {
52,247,553✔
979
            SCLogDebug("%p/%"PRIu64" skipping: ts parser not done", tx, i);
559,058✔
980
            skipped = true;
559,058✔
981
            goto next;
559,058✔
982
        }
559,058✔
983

984
        if (has_tx_detect_flags) {
51,688,495✔
985
            if (!IS_DISRUPTED(ts_disrupt_flags) &&
51,688,474✔
986
                    (f->sgh_toserver != NULL || (f->flags & FLOW_SGH_TOSERVER) == 0)) {
51,688,474✔
987
                if ((txd->flags & (APP_LAYER_TX_INSPECTED_TS | APP_LAYER_TX_SKIP_INSPECT_TS)) ==
51,594,070✔
988
                        0) {
51,594,070✔
989
                    SCLogDebug("%p/%" PRIu64 " skipping: TS inspect not done: ts:%02x", tx, i,
81,059✔
990
                            txd->flags);
81,059✔
991
                    tx_skipped = true;
81,059✔
992
                }
81,059✔
993
            }
51,594,070✔
994
            if (!IS_DISRUPTED(tc_disrupt_flags) &&
51,688,474✔
995
                    (f->sgh_toclient != NULL || (f->flags & FLOW_SGH_TOCLIENT) == 0)) {
51,688,474✔
996
                if ((txd->flags & (APP_LAYER_TX_INSPECTED_TC | APP_LAYER_TX_SKIP_INSPECT_TC)) ==
51,605,635✔
997
                        0) {
51,605,635✔
998
                    SCLogDebug("%p/%" PRIu64 " skipping: TC inspect not done: ts:%02x", tx, i,
51,471,892✔
999
                            txd->flags);
51,471,892✔
1000
                    tx_skipped = true;
51,471,892✔
1001
                }
51,471,892✔
1002
            }
51,605,635✔
1003
        }
51,688,474✔
1004

1005
        if (tx_skipped) {
51,688,495✔
1006
            SCLogDebug("%p/%" PRIu64 " tx_skipped", tx, i);
51,483,795✔
1007
            skipped = true;
51,483,795✔
1008
            goto next;
51,483,795✔
1009
        }
51,483,795✔
1010

1011
        if (logger_expectation != 0) {
204,700✔
1012
            LoggerId tx_logged = GetTxLogged(txd);
187,136✔
1013
            if (tx_logged != logger_expectation) {
187,136✔
1014
                SCLogDebug("%p/%"PRIu64" skipping: logging not done: want:%"PRIx32", have:%"PRIx32,
4,190✔
1015
                        tx, i, logger_expectation, tx_logged);
4,190✔
1016
                skipped = true;
4,190✔
1017
                goto next;
4,190✔
1018
            }
4,190✔
1019
        }
187,136✔
1020

1021
        /* if file logging is enabled, we keep a tx active while some of the files aren't
1022
         * logged yet. */
1023
        SCLogDebug("files_opened %u files_logged %u files_stored %u", txd->files_opened,
200,510✔
1024
                txd->files_logged, txd->files_stored);
200,510✔
1025

1026
        if (txd->files_opened) {
200,510✔
1027
            if (g_file_logger_enabled && txd->files_opened != txd->files_logged) {
13,695✔
1028
                skipped = true;
153✔
1029
                goto next;
153✔
1030
            }
153✔
1031
            if (g_filedata_logger_enabled && txd->files_opened != txd->files_stored) {
13,542✔
UNCOV
1032
                skipped = true;
×
UNCOV
1033
                goto next;
×
UNCOV
1034
            }
×
1035
        }
13,542✔
1036

1037
        /* if we are here, the tx can be freed. */
1038
        p->StateTransactionFree(alstate, i);
200,357✔
1039
        SCLogDebug("%p/%"PRIu64" freed", tx, i);
200,357✔
1040

1041
        /* if we didn't skip any tx so far, up the minimum */
1042
        SCLogDebug("skipped? %s i %"PRIu64", new_min %"PRIu64, skipped ? "true" : "false", i, new_min);
200,357✔
1043
        if (!skipped)
200,357✔
1044
            new_min = i + 1;
98,034✔
1045
        SCLogDebug("final i %"PRIu64", new_min %"PRIu64, i, new_min);
200,357✔
1046

1047
next:
54,548,339✔
1048
        if (!ires.has_next) {
54,548,339✔
1049
            /* this was the last tx. See if we skipped any. If not
1050
             * we removed all and can update the minimum to the max
1051
             * id. */
1052
            SCLogDebug("no next: cur tx i %"PRIu64", total %"PRIu64, i, total_txs);
555,409✔
1053
            if (!skipped) {
555,409✔
1054
                new_min = total_txs;
59,757✔
1055
                SCLogDebug("no next: cur tx i %"PRIu64", total %"PRIu64": "
59,757✔
1056
                        "new_min updated to %"PRIu64, i, total_txs, new_min);
59,757✔
1057
            }
59,757✔
1058
            break;
555,409✔
1059
        }
555,409✔
1060
        i++;
53,992,930✔
1061
    }
53,992,930✔
1062

1063
    /* see if we need to bring all trackers up to date. */
1064
    SCLogDebug("update f->alparser->min_id? %"PRIu64" vs %"PRIu64, new_min, alparser->min_id);
816,011✔
1065
    if (new_min > alparser->min_id) {
816,011✔
1066
        const uint64_t next_id = new_min;
90,496✔
1067
        alparser->min_id = next_id;
90,496✔
1068
        alparser->inspect_id[0] = MAX(alparser->inspect_id[0], next_id);
90,496✔
1069
        alparser->inspect_id[1] = MAX(alparser->inspect_id[1], next_id);
90,496✔
1070
        alparser->log_id = MAX(alparser->log_id, next_id);
90,496✔
1071
        SCLogDebug("updated f->alparser->min_id %"PRIu64, alparser->min_id);
90,496✔
1072
    }
90,496✔
1073
    SCReturn;
816,011✔
1074
}
816,007✔
1075

1076
static inline int StateGetProgressCompletionStatus(const AppProto alproto, const uint8_t flags)
1077
{
4,500,826✔
1078
    if (flags & STREAM_TOSERVER) {
4,500,826✔
1079
        return alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_ts;
2,283,792✔
1080
    } else if (flags & STREAM_TOCLIENT) {
2,283,792✔
1081
        return alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_tc;
2,217,463✔
1082
    } else {
2,149,426,171✔
1083
        DEBUG_VALIDATE_BUG_ON(1);
2,147,483,647✔
1084
        return 0;
2,147,483,647✔
1085
    }
2,147,483,647✔
1086
}
4,500,826✔
1087

1088
/**
1089
 *  \brief get the progress value for a tx/protocol
1090
 *
1091
 *  If the stream is disrupted, we return the 'completion' value.
1092
 */
1093
int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto,
1094
                        void *alstate, uint8_t flags)
1095
{
125,094,350✔
1096
    SCEnter();
125,094,350✔
1097
    int r;
125,094,350✔
1098
    if (unlikely(IS_DISRUPTED(flags))) {
125,094,350✔
1099
        r = StateGetProgressCompletionStatus(alproto, flags);
701✔
1100
    } else {
125,093,649✔
1101
        uint8_t direction = flags & (STREAM_TOCLIENT | STREAM_TOSERVER);
125,093,649✔
1102
        r = alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetProgress(
125,093,649✔
1103
                alstate, direction);
125,093,649✔
1104
    }
125,093,649✔
1105
    SCReturnInt(r);
125,094,350✔
1106
}
125,094,350✔
1107

1108
uint64_t AppLayerParserGetTxCnt(const Flow *f, void *alstate)
1109
{
4,107,554✔
1110
    SCEnter();
4,107,554✔
1111
    uint64_t r = alp_ctx.ctxs[f->alproto][f->protomap].StateGetTxCnt(alstate);
4,107,554✔
1112
    SCReturnCT(r, "uint64_t");
4,107,554✔
1113
}
4,107,554✔
1114

1115
void *AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
1116
{
311,568✔
1117
    SCEnter();
311,568✔
1118
    void *r = alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetTx(alstate, tx_id);
311,568✔
1119
    SCReturnPtr(r, "void *");
311,568✔
1120
}
311,568✔
1121

1122
int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto,
1123
                                                   uint8_t direction)
1124
{
4,499,983✔
1125
    SCEnter();
4,499,983✔
1126
    int r = StateGetProgressCompletionStatus(alproto, direction);
4,499,983✔
1127
    SCReturnInt(r);
4,499,983✔
1128
}
4,499,983✔
1129

1130
int AppLayerParserGetEventInfo(uint8_t ipproto, AppProto alproto, const char *event_name,
1131
        uint8_t *event_id, AppLayerEventType *event_type)
1132
{
89,220✔
1133
    SCEnter();
89,220✔
1134
    const int ipproto_map = FlowGetProtoMapping(ipproto);
89,220✔
1135
    int r = (alp_ctx.ctxs[alproto][ipproto_map].StateGetEventInfo == NULL)
89,220✔
1136
                    ? -1
89,220✔
1137
                    : alp_ctx.ctxs[alproto][ipproto_map].StateGetEventInfo(
89,220✔
1138
                              event_name, event_id, event_type);
88,269✔
1139
    SCReturnInt(r);
89,220✔
1140
}
89,220✔
1141

1142
int AppLayerParserGetEventInfoById(uint8_t ipproto, AppProto alproto, uint8_t event_id,
1143
        const char **event_name, AppLayerEventType *event_type)
1144
{
32,768✔
1145
    SCEnter();
32,768✔
1146
    const int ipproto_map = FlowGetProtoMapping(ipproto);
32,768✔
1147
    *event_name = (const char *)NULL;
32,768✔
1148
    int r = (alp_ctx.ctxs[alproto][ipproto_map].StateGetEventInfoById == NULL)
32,768✔
1149
                    ? -1
32,768✔
1150
                    : alp_ctx.ctxs[alproto][ipproto_map].StateGetEventInfoById(
32,768✔
1151
                              event_id, event_name, event_type);
32,768✔
1152
    SCReturnInt(r);
32,768✔
1153
}
32,768✔
1154

1155
uint8_t AppLayerParserGetFirstDataDir(uint8_t ipproto, AppProto alproto)
1156
{
30,078✔
1157
    SCEnter();
30,078✔
1158
    uint8_t r = alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].first_data_dir;
30,078✔
1159
    SCReturnCT(r, "uint8_t");
30,078✔
1160
}
30,078✔
1161

1162
uint64_t AppLayerParserGetTransactionActive(const Flow *f,
1163
        AppLayerParserState *pstate, uint8_t direction)
1164
{
12,896✔
1165
    SCEnter();
12,896✔
1166

1167
    uint64_t active_id;
12,896✔
1168
    uint64_t log_id = pstate->log_id;
12,896✔
1169
    uint64_t inspect_id = pstate->inspect_id[(direction & STREAM_TOSERVER) ? 0 : 1];
12,896✔
1170
    if (alp_ctx.ctxs[f->alproto][f->protomap].logger) {
12,896✔
1171
        active_id = MIN(log_id, inspect_id);
12,706✔
1172
    } else {
12,706✔
1173
        active_id = inspect_id;
190✔
1174
    }
190✔
1175

1176
    SCReturnCT(active_id, "uint64_t");
12,896✔
1177
}
12,896✔
1178

1179
bool AppLayerParserSupportsFiles(uint8_t ipproto, AppProto alproto)
1180
{
981,315✔
1181
    // Custom case for only signature-only protocol so far
1182
    if (alproto == ALPROTO_HTTP) {
981,315✔
1183
        return AppLayerParserSupportsFiles(ipproto, ALPROTO_HTTP1) ||
21,606✔
1184
               AppLayerParserSupportsFiles(ipproto, ALPROTO_HTTP2);
21,606✔
1185
    }
21,606✔
1186
    return alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetTxFiles != NULL;
959,709✔
1187
}
981,315✔
1188

1189
AppLayerTxData *AppLayerParserGetTxData(uint8_t ipproto, AppProto alproto, void *tx)
1190
{
72,102,629✔
1191
    SCEnter();
72,102,629✔
1192
    AppLayerTxData *d = alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetTxData(tx);
72,102,629✔
1193
    SCReturnPtr(d, "AppLayerTxData");
72,102,629✔
1194
}
72,102,629✔
1195

1196
AppLayerStateData *AppLayerParserGetStateData(uint8_t ipproto, AppProto alproto, void *state)
1197
{
47,793✔
1198
    SCEnter();
47,793✔
1199
    if (alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetStateData) {
47,798✔
1200
        AppLayerStateData *d =
47,798✔
1201
                alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetStateData(state);
47,798✔
1202
        SCReturnPtr(d, "AppLayerStateData");
47,798✔
1203
    }
47,798✔
1204
    SCReturnPtr(NULL, "AppLayerStateData");
2,147,528,153✔
1205
}
47,793✔
1206

1207
void AppLayerParserApplyTxConfig(uint8_t ipproto, AppProto alproto,
1208
        void *state, void *tx, enum ConfigAction mode, AppLayerTxConfig config)
1209
{
4✔
1210
    SCEnter();
4✔
1211
    const int ipproto_map = FlowGetProtoMapping(ipproto);
4✔
1212
    if (alp_ctx.ctxs[alproto][ipproto_map].ApplyTxConfig) {
4✔
1213
        alp_ctx.ctxs[alproto][ipproto_map].ApplyTxConfig(state, tx, mode, config);
4✔
1214
    }
4✔
1215
    SCReturn;
4✔
1216
}
4✔
1217

1218
/***** General *****/
1219

1220
static inline void SetEOFFlags(AppLayerParserState *pstate, const uint8_t flags)
1221
{
639,513✔
1222
    if ((flags & (STREAM_EOF|STREAM_TOSERVER)) == (STREAM_EOF|STREAM_TOSERVER)) {
639,513✔
1223
        SCLogDebug("setting APP_LAYER_PARSER_EOF_TS");
9,838✔
1224
        SCAppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_EOF_TS);
9,838✔
1225
    } else if ((flags & (STREAM_EOF|STREAM_TOCLIENT)) == (STREAM_EOF|STREAM_TOCLIENT)) {
629,675✔
1226
        SCLogDebug("setting APP_LAYER_PARSER_EOF_TC");
9,485✔
1227
        SCAppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_EOF_TC);
9,485✔
1228
    }
9,485✔
1229
}
639,513✔
1230

1231
/** \internal
1232
 *  \brief create/close stream frames
1233
 *  On first invocation of TCP parser in a direction, create a <alproto>.stream frame.
1234
 *  On STREAM_EOF, set the final length. */
1235
static void HandleStreamFrames(Flow *f, StreamSlice stream_slice, const uint8_t *input,
1236
        const uint32_t input_len, const uint8_t flags)
1237
{
639,485✔
1238
    const uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1;
639,485✔
1239
    AppLayerParserState *pstate = f->alparser;
639,485✔
1240

1241
    /* setup the generic stream frame */
1242
    if (((direction == 0 && (pstate->flags & APP_LAYER_PARSER_SFRAME_TS) == 0) ||
639,485✔
1243
                (direction == 1 && (pstate->flags & APP_LAYER_PARSER_SFRAME_TC) == 0)) &&
639,485✔
1244
            input != NULL && f->proto == IPPROTO_TCP) {
639,485✔
1245
        Frame *frame = AppLayerFrameGetLastOpenByType(f, direction, FRAME_STREAM_TYPE);
48,197✔
1246
        if (frame == NULL) {
48,197✔
1247
            int64_t frame_len = -1;
48,191✔
1248
            if (flags & STREAM_EOF)
48,191✔
1249
                frame_len = input_len;
1,455✔
1250

1251
            frame = AppLayerFrameNewByAbsoluteOffset(
48,191✔
1252
                    f, &stream_slice, stream_slice.offset, frame_len, direction, FRAME_STREAM_TYPE);
48,191✔
1253
            if (frame) {
48,191✔
1254
                SCLogDebug("opened: frame %p id %" PRIi64, frame, frame->id);
20,144✔
1255
                frame->flags = FRAME_FLAG_ENDS_AT_EOF; // TODO logic is not yet implemented
20,144✔
1256
                DEBUG_VALIDATE_BUG_ON(
20,144✔
1257
                        frame->id != 1); // should always be the first frame that is created
20,144✔
1258
            }
20,144✔
1259
            if (direction == 0) {
48,191✔
1260
                pstate->flags |= APP_LAYER_PARSER_SFRAME_TS;
25,673✔
1261
            } else {
25,673✔
1262
                pstate->flags |= APP_LAYER_PARSER_SFRAME_TC;
22,518✔
1263
            }
22,518✔
1264
        }
48,191✔
1265
    } else if (flags & STREAM_EOF) {
591,288✔
1266
        Frame *frame = AppLayerFrameGetLastOpenByType(f, direction, FRAME_STREAM_TYPE);
17,868✔
1267
        SCLogDebug("EOF closing: frame %p", frame);
17,868✔
1268
        if (frame) {
17,868✔
1269
            /* calculate final frame length */
1270
            int64_t slice_o = (int64_t)stream_slice.offset - (int64_t)frame->offset;
7,389✔
1271
            int64_t frame_len = slice_o + (int64_t)input_len;
7,389✔
1272
            SCLogDebug("%s: EOF frame->offset %" PRIu64 " -> %" PRIi64 ": o %" PRIi64,
7,389✔
1273
                    AppProtoToString(f->alproto), frame->offset, frame_len, slice_o);
7,389✔
1274
            frame->len = frame_len;
7,389✔
1275
        }
7,389✔
1276
    }
17,868✔
1277
}
639,485✔
1278

1279
static void Setup(Flow *f, const uint8_t direction, const uint8_t *input, uint32_t input_len,
1280
        const uint8_t flags, StreamSlice *as)
1281
{
639,475✔
1282
    memset(as, 0, sizeof(*as));
639,475✔
1283
    as->input = input;
639,475✔
1284
    as->input_len = input_len;
639,475✔
1285
    as->flags = flags;
639,475✔
1286

1287
    if (f->proto == IPPROTO_TCP && f->protoctx != NULL) {
639,475✔
1288
        TcpSession *ssn = f->protoctx;
579,183✔
1289
        TcpStream *stream = (direction & STREAM_TOSERVER) ? &ssn->client : &ssn->server;
579,183✔
1290
        as->offset = STREAM_APP_PROGRESS(stream);
579,183✔
1291
    }
579,183✔
1292
}
639,475✔
1293

1294
/** \retval int -1 in case of unrecoverable error. App-layer tracking stops for this flow.
1295
 *  \retval int 0 ok: we did not update app_progress
1296
 *  \retval int 1 ok: we updated app_progress */
1297
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto,
1298
                        uint8_t flags, const uint8_t *input, uint32_t input_len)
1299
{
652,530✔
1300
    SCEnter();
652,530✔
1301
#ifdef DEBUG_VALIDATION
1302
    BUG_ON(f->protomap != FlowGetProtoMapping(f->proto));
1303
#endif
1304
    AppLayerParserState *pstate = f->alparser;
652,530✔
1305
    AppLayerParserProtoCtx *p = &alp_ctx.ctxs[alproto][f->protomap];
652,530✔
1306
    StreamSlice stream_slice;
652,530✔
1307
    void *alstate = NULL;
652,530✔
1308
    uint64_t p_tx_cnt = 0;
652,530✔
1309
    uint32_t consumed = input_len;
652,530✔
1310
    const uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1;
652,530✔
1311

1312
    /* we don't have the parser registered for this protocol */
1313
    if (p->StateAlloc == NULL) {
652,530✔
1314
        if (f->proto == IPPROTO_TCP) {
12,214✔
1315
            StreamTcpDisableAppLayer(f);
5✔
1316
        }
5✔
1317
        goto end;
12,214✔
1318
    }
12,214✔
1319

1320
    if (flags & STREAM_GAP) {
640,316✔
1321
        if (!(p->option_flags & APP_LAYER_PARSER_OPT_ACCEPT_GAPS)) {
9,298✔
1322
            SCLogDebug("app-layer parser does not accept gaps");
802✔
1323
            if (f->alstate != NULL && !FlowChangeProto(f)) {
802✔
1324
                SCAppLayerParserTriggerRawStreamInspection(f, direction);
795✔
1325
            }
795✔
1326
            AppLayerIncGapErrorCounter(tv, f);
802✔
1327
            goto error;
802✔
1328
        }
802✔
1329
    }
9,298✔
1330

1331
    /* Get the parser state (if any) */
1332
    if (pstate == NULL) {
639,514✔
1333
        f->alparser = pstate = AppLayerParserStateAlloc();
37,476✔
1334
        if (pstate == NULL) {
37,476✔
1335
            AppLayerIncAllocErrorCounter(tv, f);
×
1336
            goto error;
×
1337
        }
×
1338
    }
37,476✔
1339

1340
    SetEOFFlags(pstate, flags);
639,514✔
1341

1342
    alstate = f->alstate;
639,514✔
1343
    if (alstate == NULL || FlowChangeProto(f)) {
639,514✔
1344
        f->alstate = alstate = p->StateAlloc(alstate, f->alproto_orig);
37,469✔
1345
        if (alstate == NULL) {
37,469✔
1346
            AppLayerIncAllocErrorCounter(tv, f);
×
1347
            goto error;
×
1348
        }
×
1349
        SCLogDebug("alloced new app layer state %p (name %s)",
37,469✔
1350
                   alstate, AppLayerGetProtoName(f->alproto));
37,469✔
1351

1352
        /* set flow flags to state */
1353
        if (f->file_flags != 0) {
37,469✔
1354
            AppLayerStateData *sd = AppLayerParserGetStateData(f->proto, f->alproto, f->alstate);
26,782✔
1355
            if (sd != NULL) {
26,782✔
1356
                if ((sd->file_flags & f->file_flags) != f->file_flags) {
26,778✔
1357
                    SCLogDebug("state data: updating file_flags %04x with flow file_flags %04x",
26,778✔
1358
                            sd->file_flags, f->file_flags);
26,778✔
1359
                    sd->file_flags |= f->file_flags;
26,778✔
1360
                }
26,778✔
1361
            }
26,778✔
1362
        }
26,782✔
1363
    } else {
602,045✔
1364
        SCLogDebug("using existing app layer state %p (name %s))",
602,045✔
1365
                   alstate, AppLayerGetProtoName(f->alproto));
602,045✔
1366
    }
602,045✔
1367

1368
    p_tx_cnt = AppLayerParserGetTxCnt(f, f->alstate);
639,514✔
1369

1370
    /* invoke the recursive parser, but only on data. We may get empty msgs on EOF */
1371
    if (input_len > 0 || (flags & STREAM_EOF)) {
639,514✔
1372
        Setup(f, flags & (STREAM_TOSERVER | STREAM_TOCLIENT), input, input_len, flags,
639,481✔
1373
                &stream_slice);
639,481✔
1374
        HandleStreamFrames(f, stream_slice, input, input_len, flags);
639,481✔
1375

1376
#ifdef QA_SIMULATION
1377
        if (((stream_slice.flags & STREAM_TOSERVER) &&
1378
                    stream_slice.offset >= g_eps_applayer_error_offset_ts)) {
1379
            SCLogNotice("putting parser %s into an error state from toserver offset %" PRIu64,
1380
                    AppProtoToString(alproto), g_eps_applayer_error_offset_ts);
1381
            AppLayerIncParserErrorCounter(tv, f);
1382
            goto error;
1383
        }
1384
        if (((stream_slice.flags & STREAM_TOCLIENT) &&
1385
                    stream_slice.offset >= g_eps_applayer_error_offset_tc)) {
1386
            SCLogNotice("putting parser %s into an error state from toclient offset %" PRIu64,
1387
                    AppProtoToString(alproto), g_eps_applayer_error_offset_tc);
1388
            AppLayerIncParserErrorCounter(tv, f);
1389
            goto error;
1390
        }
1391
#endif
1392
        /* invoke the parser */
1393
        AppLayerResult res = p->Parser[direction](f, alstate, pstate, stream_slice,
639,481✔
1394
                alp_tctx->alproto_local_storage[alproto][f->protomap]);
639,481✔
1395
        if (res.status < 0) {
639,481✔
1396
            AppLayerIncParserErrorCounter(tv, f);
5,032✔
1397
            goto error;
5,032✔
1398
        } else if (res.status > 0) {
634,449✔
1399
            DEBUG_VALIDATE_BUG_ON(res.consumed > input_len);
10,015✔
1400
            DEBUG_VALIDATE_BUG_ON(res.needed + res.consumed < input_len);
10,015✔
1401
            DEBUG_VALIDATE_BUG_ON(res.needed == 0);
10,015✔
1402
            /* incomplete is only supported for TCP */
1403
            DEBUG_VALIDATE_BUG_ON(f->proto != IPPROTO_TCP);
10,015✔
1404

1405
            /* put protocol in error state on improper use of the
1406
             * return codes. */
1407
            if (res.consumed > input_len || res.needed + res.consumed < input_len) {
10,015✔
1408
                AppLayerIncInternalErrorCounter(tv, f);
×
1409
                goto error;
×
1410
            }
×
1411

1412
            if (f->proto == IPPROTO_TCP && f->protoctx != NULL) {
10,015✔
1413
                TcpSession *ssn = f->protoctx;
10,015✔
1414
                SCLogDebug("direction %d/%s", direction,
10,015✔
1415
                        (flags & STREAM_TOSERVER) ? "toserver" : "toclient");
10,015✔
1416
                if (direction == 0) {
10,015✔
1417
                    /* parser told us how much data it needs on top of what it
1418
                     * consumed. So we need tell stream engine how much we need
1419
                     * before the next call */
1420
                    ssn->client.data_required = res.needed;
3,981✔
1421
                    SCLogDebug("setting data_required %u", ssn->client.data_required);
3,981✔
1422
                } else {
6,034✔
1423
                    /* parser told us how much data it needs on top of what it
1424
                     * consumed. So we need tell stream engine how much we need
1425
                     * before the next call */
1426
                    ssn->server.data_required = res.needed;
6,034✔
1427
                    SCLogDebug("setting data_required %u", ssn->server.data_required);
6,034✔
1428
                }
6,034✔
1429
            }
10,015✔
1430
            consumed = res.consumed;
10,015✔
1431
        }
10,015✔
1432
    }
639,481✔
1433

1434
    /* set the packets to no inspection and reassembly if required */
1435
    if (pstate->flags & APP_LAYER_PARSER_NO_INSPECTION) {
634,482✔
1436
        AppLayerParserSetEOF(pstate);
1,090✔
1437

1438
        if (f->proto == IPPROTO_TCP) {
1,090✔
1439
            StreamTcpDisableAppLayer(f);
46✔
1440

1441
            /* Set the no reassembly flag for both the stream in this TcpSession */
1442
            if (pstate->flags & APP_LAYER_PARSER_NO_REASSEMBLY) {
46✔
1443
                /* Used only if it's TCP */
UNCOV
1444
                TcpSession *ssn = f->protoctx;
×
UNCOV
1445
                if (ssn != NULL) {
×
UNCOV
1446
                    StreamTcpSetSessionNoReassemblyFlag(ssn, 0);
×
UNCOV
1447
                    StreamTcpSetSessionNoReassemblyFlag(ssn, 1);
×
UNCOV
1448
                }
×
UNCOV
1449
            }
×
1450
            /* Set the bypass flag for both the stream in this TcpSession */
1451
            if (pstate->flags & APP_LAYER_PARSER_BYPASS_READY) {
46✔
1452
                /* Used only if it's TCP */
UNCOV
1453
                TcpSession *ssn = f->protoctx;
×
UNCOV
1454
                if (ssn != NULL) {
×
UNCOV
1455
                    StreamTcpSetSessionBypassFlag(ssn);
×
UNCOV
1456
                }
×
UNCOV
1457
            }
×
1458
        } else {
1,045✔
1459
            // for TCP, this is set after flushing
1460
            FlowSetNoPayloadInspectionFlag(f);
1,044✔
1461
        }
1,044✔
1462
    }
1,090✔
1463

1464
    /* In cases like HeartBleed for TLS we need to inspect AppLayer but not Payload */
1465
    if (!(f->flags & FLOW_NOPAYLOAD_INSPECTION) && pstate->flags & APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD) {
634,482✔
1466
        FlowSetNoPayloadInspectionFlag(f);
1,838✔
1467
        /* Set the no reassembly flag for both the stream in this TcpSession */
1468
        if (f->proto == IPPROTO_TCP) {
1,838✔
1469
            /* Used only if it's TCP */
1470
            TcpSession *ssn = f->protoctx;
1,838✔
1471
            if (ssn != NULL) {
1,838✔
1472
                StreamTcpSetDisableRawReassemblyFlag(ssn, 0);
1,838✔
1473
                StreamTcpSetDisableRawReassemblyFlag(ssn, 1);
1,838✔
1474
            }
1,838✔
1475
        }
1,838✔
1476
    }
1,838✔
1477

1478
    /* get the diff in tx cnt for stats keeping */
1479
    uint64_t cur_tx_cnt = AppLayerParserGetTxCnt(f, f->alstate);
634,482✔
1480
    if (cur_tx_cnt > p_tx_cnt && tv) {
634,482✔
1481
        AppLayerIncTxCounter(tv, f, cur_tx_cnt - p_tx_cnt);
210,333✔
1482
    }
210,333✔
1483

1484
 end:
646,715✔
1485
    /* update app progress */
1486
    if (consumed != input_len && f->proto == IPPROTO_TCP && f->protoctx != NULL) {
646,715✔
1487
        TcpSession *ssn = f->protoctx;
9,995✔
1488
        StreamTcpUpdateAppLayerProgress(ssn, direction, consumed);
9,995✔
1489
        SCReturnInt(1);
9,995✔
1490
    }
9,995✔
1491

1492
    SCReturnInt(0);
646,715✔
1493
 error:
5,834✔
1494
    /* Set the no app layer inspection flag for both
1495
     * the stream in this Flow */
1496
    if (f->proto == IPPROTO_TCP) {
5,834✔
1497
        StreamTcpDisableAppLayer(f);
3,205✔
1498
    }
3,205✔
1499
    AppLayerParserSetEOF(pstate);
5,834✔
1500
    SCReturnInt(-1);
5,834✔
1501
}
646,715✔
1502

1503
void AppLayerParserSetEOF(AppLayerParserState *pstate)
1504
{
6,924✔
1505
    SCEnter();
6,924✔
1506

1507
    if (pstate == NULL)
6,924✔
1508
        goto end;
7✔
1509

1510
    SCLogDebug("setting APP_LAYER_PARSER_EOF_TC and APP_LAYER_PARSER_EOF_TS");
6,917✔
1511
    SCAppLayerParserStateSetFlag(pstate, (APP_LAYER_PARSER_EOF_TS | APP_LAYER_PARSER_EOF_TC));
6,917✔
1512

1513
 end:
6,924✔
1514
    SCReturn;
6,924✔
1515
}
6,917✔
1516

1517
/* return true if there are app parser decoder events. These are
1518
 * only the ones that are set during protocol detection. */
1519
bool AppLayerParserHasDecoderEvents(AppLayerParserState *pstate)
1520
{
3,999,788✔
1521
    SCEnter();
3,999,788✔
1522

1523
    if (pstate == NULL)
3,999,788✔
1524
        return false;
744,920✔
1525

1526
    const AppLayerDecoderEvents *decoder_events = AppLayerParserGetDecoderEvents(pstate);
3,254,868✔
1527
    if (decoder_events && decoder_events->cnt)
3,254,868✔
1528
        return true;
×
1529

1530
    /* if we have reached here, we don't have events */
1531
    return false;
3,254,868✔
1532
}
3,254,868✔
1533

1534
/** \brief simple way to globally test if a alproto is registered
1535
 *         and fully enabled in the configuration.
1536
 */
1537
int AppLayerParserIsEnabled(AppProto alproto)
1538
{
37,758✔
1539
    for (int i = 0; i < FLOW_PROTO_APPLAYER_MAX; i++) {
47,541✔
1540
        if (alp_ctx.ctxs[alproto][i].StateGetProgress != NULL) {
47,541✔
1541
            return 1;
37,758✔
1542
        }
37,758✔
1543
    }
47,541✔
UNCOV
1544
    return 0;
×
1545
}
37,758✔
1546

1547
int AppLayerParserProtocolHasLogger(uint8_t ipproto, AppProto alproto)
1548
{
78,396✔
1549
    SCEnter();
78,396✔
1550
    int ipproto_map = FlowGetProtoMapping(ipproto);
78,396✔
1551
    int r = (!alp_ctx.ctxs[alproto][ipproto_map].logger) ? 0 : 1;
78,396✔
1552
    SCReturnInt(r);
78,396✔
1553
}
78,396✔
1554

1555
LoggerId AppLayerParserProtocolGetLoggerBits(uint8_t ipproto, AppProto alproto)
1556
{
1,677,766✔
1557
    SCEnter();
1,677,766✔
1558
    const int ipproto_map = FlowGetProtoMapping(ipproto);
1,677,766✔
1559
    LoggerId r = alp_ctx.ctxs[alproto][ipproto_map].logger_bits;
1,677,766✔
1560
    SCReturnUInt(r);
1,677,766✔
1561
}
1,677,766✔
1562

1563
void SCAppLayerParserTriggerRawStreamInspection(Flow *f, int direction)
1564
{
182,568✔
1565
    SCEnter();
182,568✔
1566

1567
    SCLogDebug("f %p tcp %p direction %d", f, f ? f->protoctx : NULL, direction);
182,568✔
1568
    if (f != NULL && f->protoctx != NULL)
182,568✔
1569
        StreamTcpReassembleTriggerRawInspection(f->protoctx, direction);
178,510✔
1570

1571
    SCReturn;
182,568✔
1572
}
182,568✔
1573

1574
void SCAppLayerParserSetStreamDepth(uint8_t ipproto, AppProto alproto, uint32_t stream_depth)
1575
{
53✔
1576
    SCEnter();
53✔
1577

1578
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].stream_depth = stream_depth;
53✔
1579
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].internal_flags |=
53✔
1580
            APP_LAYER_PARSER_INT_STREAM_DEPTH_SET;
53✔
1581

1582
    SCReturn;
53✔
1583
}
53✔
1584

1585
uint32_t AppLayerParserGetStreamDepth(const Flow *f)
1586
{
46,437✔
1587
    SCReturnInt(alp_ctx.ctxs[f->alproto][f->protomap].stream_depth);
46,437✔
1588
}
46,437✔
1589

1590
void AppLayerParserSetStreamDepthFlag(uint8_t ipproto, AppProto alproto, void *state, uint64_t tx_id, uint8_t flags)
1591
{
721✔
1592
    SCEnter();
721✔
1593
    void *tx = NULL;
721✔
1594
    if (state != NULL) {
721✔
1595
        if ((tx = AppLayerParserGetTx(ipproto, alproto, state, tx_id)) != NULL) {
721✔
1596
            if (alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].SetStreamDepthFlag != NULL) {
721✔
1597
                alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].SetStreamDepthFlag(tx, flags);
163✔
1598
            }
163✔
1599
        }
721✔
1600
    }
721✔
1601
    SCReturn;
721✔
1602
}
721✔
1603

1604
/**
1605
 *  \param id progress value id to get the name for
1606
 *  \param direction STREAM_TOSERVER/STREAM_TOCLIENT
1607
 */
1608
int AppLayerParserGetStateIdByName(
1609
        uint8_t ipproto, AppProto alproto, const char *name, const uint8_t direction)
1610
{
481✔
1611
    if (alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetStateIdByName != NULL) {
481✔
1612
        return alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetStateIdByName(
379✔
1613
                name, direction);
379✔
1614
    } else {
379✔
1615
        return -1;
102✔
1616
    }
102✔
1617
}
481✔
1618

1619
/**
1620
 *  \param id progress value id to get the name for
1621
 *  \param direction STREAM_TOSERVER/STREAM_TOCLIENT
1622
 */
1623
const char *AppLayerParserGetStateNameById(
1624
        uint8_t ipproto, AppProto alproto, const int id, const uint8_t direction)
1625
{
70,242✔
1626
    if (alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetStateNameById != NULL) {
70,242✔
1627
        return alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetStateNameById(id, direction);
7,062✔
1628
    } else {
63,345✔
1629
        return NULL;
63,180✔
1630
    }
63,180✔
1631
}
70,242✔
1632

1633
int AppLayerParserGetFrameIdByName(uint8_t ipproto, AppProto alproto, const char *name)
1634
{
42,755✔
1635
    if (alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetFrameIdByName != NULL) {
42,755✔
1636
        return alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetFrameIdByName(name);
42,130✔
1637
    } else {
42,130✔
1638
        return -1;
625✔
1639
    }
625✔
1640
}
42,755✔
1641

1642
const char *AppLayerParserGetFrameNameById(uint8_t ipproto, AppProto alproto, const uint8_t id)
1643
{
1,747✔
1644
    if (alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetFrameNameById != NULL) {
1,747✔
1645
        return alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetFrameNameById(id);
1,747✔
1646
    } else {
1,747✔
UNCOV
1647
        return NULL;
×
UNCOV
1648
    }
×
1649
}
1,747✔
1650

1651
/***** Cleanup *****/
1652

1653
void AppLayerParserStateProtoCleanup(
1654
        uint8_t protomap, AppProto alproto, void *alstate, AppLayerParserState *pstate)
1655
{
112,206✔
1656
    SCEnter();
112,206✔
1657

1658
    AppLayerParserProtoCtx *ctx = &alp_ctx.ctxs[alproto][protomap];
112,206✔
1659

1660
    if (ctx->StateFree != NULL && alstate != NULL)
112,206✔
1661
        ctx->StateFree(alstate);
37,482✔
1662

1663
    /* free the app layer parser api state */
1664
    if (pstate != NULL)
112,206✔
1665
        AppLayerParserStateFree(pstate);
37,482✔
1666

1667
    SCReturn;
112,206✔
1668
}
112,206✔
1669

1670
void AppLayerParserStateCleanup(const Flow *f, void *alstate, AppLayerParserState *pstate)
1671
{
111,035✔
1672
    AppLayerParserStateProtoCleanup(f->protomap, f->alproto, alstate, pstate);
111,035✔
1673
}
111,035✔
1674

1675
static void ValidateParserProtoDump(AppProto alproto, uint8_t ipproto)
1676
{
×
1677
    uint8_t map = FlowGetProtoMapping(ipproto);
×
1678
    const AppLayerParserProtoCtx *ctx = &alp_ctx.ctxs[alproto][map];
×
1679
    printf("ERROR: incomplete app-layer registration\n");
×
1680
    printf("AppLayer protocol %s ipproto %u\n", AppProtoToString(alproto), ipproto);
×
1681
    printf("- option flags %"PRIx32"\n", ctx->option_flags);
×
1682
    printf("- first_data_dir %"PRIx8"\n", ctx->first_data_dir);
×
1683
    printf("Mandatory:\n");
×
1684
    printf("- Parser[0] %p Parser[1] %p\n", ctx->Parser[0], ctx->Parser[1]);
×
1685
    printf("- StateAlloc %p StateFree %p\n", ctx->StateAlloc, ctx->StateFree);
×
1686
    printf("- StateGetTx %p StateGetTxCnt %p StateTransactionFree %p\n",
×
1687
            ctx->StateGetTx, ctx->StateGetTxCnt, ctx->StateTransactionFree);
×
1688
    printf("- GetTxData %p\n", ctx->GetTxData);
×
1689
    printf("- GetStateData %p\n", ctx->GetStateData);
×
1690
    printf("- StateGetProgress %p\n", ctx->StateGetProgress);
×
1691
    printf("Optional:\n");
×
1692
    printf("- LocalStorageAlloc %p LocalStorageFree %p\n", ctx->LocalStorageAlloc, ctx->LocalStorageFree);
×
1693
    printf("- StateGetEventInfo %p StateGetEventInfoById %p\n", ctx->StateGetEventInfo,
×
1694
            ctx->StateGetEventInfoById);
×
1695
}
×
1696

1697
#define BOTH_SET(a, b) ((a) != NULL && (b) != NULL)
3,310✔
1698
#define BOTH_SET_OR_BOTH_UNSET(a, b) (((a) == NULL && (b) == NULL) || ((a) != NULL && (b) != NULL))
1,655✔
1699
#define THREE_SET(a, b, c) ((a) != NULL && (b) != NULL && (c) != NULL)
1,655✔
1700

1701
static void ValidateParserProto(AppProto alproto, uint8_t ipproto)
1702
{
3,520✔
1703
    uint8_t map = FlowGetProtoMapping(ipproto);
3,520✔
1704
    const AppLayerParserProtoCtx *ctx = &alp_ctx.ctxs[alproto][map];
3,520✔
1705

1706
    if (ctx->Parser[0] == NULL && ctx->Parser[1] == NULL)
3,520✔
1707
        return;
1,865✔
1708

1709
    if (!(BOTH_SET(ctx->Parser[0], ctx->Parser[1]))) {
1,655✔
1710
        goto bad;
×
1711
    }
×
1712
    if (!(BOTH_SET(ctx->StateFree, ctx->StateAlloc))) {
1,655✔
1713
        goto bad;
×
1714
    }
×
1715
    if (!(THREE_SET(ctx->StateGetTx, ctx->StateGetTxCnt, ctx->StateTransactionFree))) {
1,655✔
1716
        goto bad;
×
1717
    }
×
1718
    if (ctx->StateGetProgress == NULL) {
1,655✔
1719
        goto bad;
×
1720
    }
×
1721
    /* local storage is optional, but needs both set if used */
1722
    if (!(BOTH_SET_OR_BOTH_UNSET(ctx->LocalStorageAlloc, ctx->LocalStorageFree))) {
1,655✔
1723
        goto bad;
×
1724
    }
×
1725
    if (ctx->GetTxData == NULL) {
1,655✔
1726
        goto bad;
×
1727
    }
×
1728
    if (ctx->GetStateData == NULL) {
1,655✔
1729
        goto bad;
×
1730
    }
×
1731
    return;
1,655✔
1732
bad:
1,655✔
1733
    ValidateParserProtoDump(alproto, ipproto);
×
1734
    exit(EXIT_FAILURE);
×
1735
}
1,655✔
1736
#undef BOTH_SET
1737
#undef BOTH_SET_OR_BOTH_UNSET
1738
#undef THREE_SET
1739

1740
static void ValidateParser(AppProto alproto)
1741
{
1,760✔
1742
    ValidateParserProto(alproto, IPPROTO_TCP);
1,760✔
1743
    ValidateParserProto(alproto, IPPROTO_UDP);
1,760✔
1744
}
1,760✔
1745

1746
static void ValidateParsers(void)
1747
{
44✔
1748
    AppProto p = 0;
44✔
1749
    for (; p < g_alproto_max; p++) {
1,804✔
1750
        ValidateParser(p);
1,760✔
1751
    }
1,760✔
1752
}
44✔
1753

1754
#define ARRAY_CAP_STEP 16
88✔
1755
static void (**PreRegisteredCallbacks)(void) = NULL;
1756
static size_t preregistered_callbacks_nb = 0;
1757
static size_t preregistered_callbacks_cap = 0;
1758

1759
int SCAppLayerParserReallocCtx(AppProto alproto)
1760
{
44✔
1761
    if (alp_ctx.ctxs_len <= alproto && alproto < g_alproto_max) {
44✔
1762
        /* Realloc alp_ctx.ctxs, so that dynamic alproto can be treated as real/normal ones.
1763
         * In case we need to turn off dynamic alproto. */
1764
        void *tmp = SCRealloc(alp_ctx.ctxs, sizeof(AppLayerParserProtoCtx[FLOW_PROTO_MAX]) *
44✔
1765
                                                    (alp_ctx.ctxs_len + ARRAY_CAP_STEP));
44✔
1766
        if (unlikely(tmp == NULL)) {
44✔
1767
            FatalError("Unable to realloc alp_ctx.ctxs.");
×
1768
        }
×
1769
        alp_ctx.ctxs = tmp;
44✔
1770
        memset(&alp_ctx.ctxs[alp_ctx.ctxs_len], 0,
44✔
1771
                sizeof(AppLayerParserProtoCtx[FLOW_PROTO_MAX]) * ARRAY_CAP_STEP);
44✔
1772
        alp_ctx.ctxs_len += ARRAY_CAP_STEP;
44✔
1773
    }
44✔
1774
    return 0;
44✔
1775
}
44✔
1776

1777
int AppLayerParserPreRegister(void (*Register)(void))
1778
{
×
1779
    if (preregistered_callbacks_nb == preregistered_callbacks_cap) {
×
1780
        void *tmp = SCRealloc(PreRegisteredCallbacks,
×
1781
                sizeof(void *) * (preregistered_callbacks_cap + ARRAY_CAP_STEP));
×
1782
        if (tmp == NULL) {
×
1783
            return 1;
×
1784
        }
×
1785
        preregistered_callbacks_cap += ARRAY_CAP_STEP;
×
1786
        PreRegisteredCallbacks = tmp;
×
1787
    }
×
1788
    PreRegisteredCallbacks[preregistered_callbacks_nb] = Register;
×
1789
    preregistered_callbacks_nb++;
×
1790
    return 0;
×
1791
}
×
1792

1793
void AppLayerParserRegisterProtocolParsers(void)
1794
{
44✔
1795
    SCEnter();
44✔
1796

1797
    AppLayerConfig();
44✔
1798

1799
    RegisterHTPParsers();
44✔
1800
    RegisterSSLParsers();
44✔
1801
    SCRegisterDcerpcParser();
44✔
1802
    SCRegisterDcerpcUdpParser();
44✔
1803
    RegisterSMBParsers();
44✔
1804
    RegisterFTPParsers();
44✔
1805
    RegisterSSHParsers();
44✔
1806
    RegisterSMTPParsers();
44✔
1807
    SCRegisterDnsUdpParser();
44✔
1808
    SCRegisterDnsTcpParser();
44✔
1809
    SCRegisterBittorrentDhtUdpParser();
44✔
1810
    RegisterModbusParsers();
44✔
1811
    SCEnipRegisterParsers();
44✔
1812
    RegisterDNP3Parsers();
44✔
1813
    RegisterNFSTCPParsers();
44✔
1814
    RegisterNFSUDPParsers();
44✔
1815
    SCRegisterNtpParser();
44✔
1816
    RegisterTFTPParsers();
44✔
1817
    RegisterIKEParsers();
44✔
1818
    SCRegisterKrb5Parser();
44✔
1819
    SCRegisterDhcpParser();
44✔
1820
    SCRegisterSnmpParser();
44✔
1821
    SCRegisterSipParser();
44✔
1822
    SCRegisterQuicParser();
44✔
1823
    SCRegisterWebSocketParser();
44✔
1824
    SCRegisterLdapTcpParser();
44✔
1825
    SCRegisterLdapUdpParser();
44✔
1826
    SCRegisterMdnsParser();
44✔
1827
    SCRegisterTemplateParser();
44✔
1828
    SCRfbRegisterParser();
44✔
1829
    SCMqttRegisterParser();
44✔
1830
    SCRegisterPgsqlParser();
44✔
1831
    SCRegisterPop3Parser();
44✔
1832
    SCRegisterRdpParser();
44✔
1833
    RegisterHTTP2Parsers();
44✔
1834
    SCRegisterTelnetParser();
44✔
1835
    RegisterIMAPParsers();
44✔
1836

1837
    for (size_t i = 0; i < preregistered_callbacks_nb; i++) {
44✔
1838
        PreRegisteredCallbacks[i]();
×
1839
    }
×
1840

1841
    ValidateParsers();
44✔
1842
}
44✔
1843

1844
/* coccinelle: SCAppLayerParserStateSetFlag():2,2:APP_LAYER_PARSER_ */
1845
void SCAppLayerParserStateSetFlag(AppLayerParserState *pstate, uint16_t flag)
1846
{
72,315✔
1847
    SCEnter();
72,315✔
1848
    pstate->flags |= flag;
72,315✔
1849
    SCReturn;
72,315✔
1850
}
72,315✔
1851

1852
/* coccinelle: SCAppLayerParserStateIssetFlag():2,2:APP_LAYER_PARSER_ */
1853
uint16_t SCAppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint16_t flag)
1854
{
4,631,086✔
1855
    SCEnter();
4,631,086✔
1856
    SCReturnUInt(pstate->flags & flag);
4,631,086✔
1857
}
4,631,086✔
1858

1859
/***** Unittests *****/
1860

1861
#ifdef UNITTESTS
1862
#include "util-unittest-helper.h"
1863

1864
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto,
1865
                                  void (*RegisterUnittests)(void))
1866
{
49✔
1867
    SCEnter();
49✔
1868
    alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].RegisterUnittests = RegisterUnittests;
49✔
1869
    SCReturn;
49✔
1870
}
49✔
1871

1872
void AppLayerParserRegisterUnittests(void)
1873
{
1✔
1874
    SCEnter();
1✔
1875

1876
    int ip;
1✔
1877
    AppProto alproto;
1✔
1878
    AppLayerParserProtoCtx *ctx;
1✔
1879

1880
    for (ip = 0; ip < FLOW_PROTO_DEFAULT; ip++) {
4✔
1881
        for (alproto = 0; alproto < g_alproto_max; alproto++) {
123✔
1882
            ctx = &alp_ctx.ctxs[alproto][ip];
120✔
1883
            if (ctx->RegisterUnittests == NULL)
120✔
1884
                continue;
111✔
1885
            ctx->RegisterUnittests();
9✔
1886
        }
9✔
1887
    }
3✔
1888

1889
    SCReturn;
1✔
1890
}
1✔
1891

1892
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc