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

OISF / suricata / 22712336922

05 Mar 2026 09:55AM UTC coverage: 66.796% (-12.5%) from 79.283%
22712336922

Pull #14946

github

web-flow
Merge 91559149c into 7e97dfd52
Pull Request #14946: Stack 8001 v15

14 of 19 new or added lines in 7 files covered. (73.68%)

11298 existing lines in 298 files now uncovered.

155282 of 232473 relevant lines covered (66.8%)

5923441.93 hits per line

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

82.61
/src/detect-engine-state.c
1
/* Copyright (C) 2007-2021 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
 * \defgroup sigstate State support
20
 *
21
 * State is stored in the ::DetectEngineState structure. This is
22
 * basically a container for storage item of type ::DeStateStore.
23
 * They contains an array of ::DeStateStoreItem which store the
24
 * state of match for an individual signature identified by
25
 * DeStateStoreItem::sid.
26
 *
27
 * @{
28
 */
29

30
/**
31
 * \file
32
 *
33
 * \author Victor Julien <victor@inliniac.net>
34
 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
35
 *
36
 * \brief State based signature handling.
37
 */
38

39
#include "suricata-common.h"
40

41
#include "decode.h"
42

43
#include "detect.h"
44
#include "detect-engine.h"
45
#include "detect-parse.h"
46
#include "detect-engine-state.h"
47
#include "detect-engine-dcepayload.h"
48
#include "detect-engine-build.h"
49

50
#include "detect-flowvar.h"
51

52
#include "stream-tcp.h"
53
#include "stream-tcp-private.h"
54
#include "stream-tcp-reassemble.h"
55

56
#include "app-layer.h"
57
#include "app-layer-parser.h"
58
#include "app-layer-protos.h"
59
#include "app-layer-htp.h"
60

61
#include "util-unittest.h"
62
#include "util-unittest-helper.h"
63
#include "util-profiling.h"
64

65
#include "flow-util.h"
66

67
static inline int StateIsValid(uint16_t alproto, void *alstate)
68
{
1,482✔
69
    if (alstate != NULL) {
1,482✔
70
        if (alproto == ALPROTO_HTTP1) {
1,299✔
71
            HtpState *htp_state = (HtpState *)alstate;
255✔
72
            if (htp_state->conn != NULL) {
255✔
73
                return 1;
255✔
74
            }
255✔
75
        } else {
1,047✔
76
            return 1;
1,044✔
77
        }
1,044✔
78
    }
1,299✔
79
    return 0;
183✔
80
}
1,482✔
81

82
static DeStateStore *DeStateStoreAlloc(void)
83
{
28,015✔
84
    DeStateStore *d = SCCalloc(1, sizeof(DeStateStore));
28,015✔
85
    if (unlikely(d == NULL))
28,015✔
86
        return NULL;
×
87

88
    return d;
28,015✔
89
}
28,015✔
90

91
#ifdef DEBUG_VALIDATION
92
static int DeStateSearchState(DetectEngineState *state, uint8_t direction, SigIntId num)
93
{
94
    DetectEngineStateDirection *dir_state = &state->dir_state[direction & STREAM_TOSERVER ? 0 : 1];
95
    DeStateStore *tx_store = dir_state->head;
96
    SigIntId store_cnt;
97
    SigIntId state_cnt = 0;
98

99
    for (; tx_store != NULL; tx_store = tx_store->next) {
100
        SCLogDebug("tx_store %p", tx_store);
101
        for (store_cnt = 0;
102
             store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < dir_state->cnt;
103
             store_cnt++, state_cnt++)
104
        {
105
            DeStateStoreItem *item = &tx_store->store[store_cnt];
106
            if (item->sid == num) {
107
                SCLogDebug("sid %u already in state: %p %p %p %u %u, direction %s",
108
                            num, state, dir_state, tx_store, state_cnt,
109
                            store_cnt, direction & STREAM_TOSERVER ? "toserver" : "toclient");
110
                return 1;
111
            }
112
        }
113
    }
114
    return 0;
115
}
116
#endif
117

118
static void DeStateSignatureAppend(DetectEngineState *state,
119
        const Signature *s, uint32_t inspect_flags, uint8_t direction)
120
{
40,513✔
121
    SCEnter();
40,513✔
122

123
    DetectEngineStateDirection *dir_state =
40,513✔
124
            &state->dir_state[(direction & STREAM_TOSERVER) ? 0 : 1];
40,513✔
125

126
#ifdef DEBUG_VALIDATION
127
    BUG_ON(DeStateSearchState(state, direction, s->iid));
128
#endif
129
    DeStateStore *store = dir_state->tail;
40,513✔
130
    if (store == NULL) {
40,513✔
131
        store = DeStateStoreAlloc();
28,015✔
132
        dir_state->head = store;
28,015✔
133
        dir_state->cur = store;
28,015✔
134
        dir_state->tail = store;
28,015✔
135
    } else if (dir_state->cur) {
28,015✔
136
        store = dir_state->cur;
12,498✔
137
    } else {
12,498✔
UNCOV
138
        store = DeStateStoreAlloc();
×
UNCOV
139
        if (store != NULL) {
×
UNCOV
140
            dir_state->tail->next = store;
×
UNCOV
141
            dir_state->tail = store;
×
UNCOV
142
            dir_state->cur = store;
×
UNCOV
143
        }
×
UNCOV
144
    }
×
145
    if (store == NULL)
40,513✔
146
        SCReturn;
×
147

148
    SigIntId idx = dir_state->cnt % DE_STATE_CHUNK_SIZE;
40,513✔
149
    store->store[idx].sid = s->iid;
40,513✔
150
    store->store[idx].flags = inspect_flags;
40,513✔
151
    dir_state->cnt++;
40,513✔
152
    /* if current chunk is full, progress cur */
153
    if (dir_state->cnt % DE_STATE_CHUNK_SIZE == 0) {
40,513✔
UNCOV
154
        dir_state->cur = dir_state->cur->next;
×
UNCOV
155
    }
×
156

157
    SCReturn;
40,513✔
158
}
40,513✔
159

160
DetectEngineState *DetectEngineStateAlloc(void)
161
{
19,244✔
162
    DetectEngineState *d = SCCalloc(1, sizeof(DetectEngineState));
19,244✔
163
    if (unlikely(d == NULL))
19,244✔
164
        return NULL;
×
165

166
    return d;
19,244✔
167
}
19,244✔
168

169
void SCDetectEngineStateFree(DetectEngineState *state)
170
{
19,244✔
171
    DeStateStore *store;
19,244✔
172
    DeStateStore *store_next;
19,244✔
173
    int i = 0;
19,244✔
174

175
    for (i = 0; i < 2; i++) {
57,732✔
176
        store = state->dir_state[i].head;
38,488✔
177
        while (store != NULL) {
66,503✔
178
            store_next = store->next;
28,015✔
179
            SCFree(store);
28,015✔
180
            store = store_next;
28,015✔
181
        }
28,015✔
182
    }
38,488✔
183
    SCFree(state);
19,244✔
184
}
19,244✔
185

186
static void StoreFileNoMatchCnt(DetectEngineState *de_state, uint16_t file_no_match, uint8_t direction)
187
{
40,500✔
188
    de_state->dir_state[(direction & STREAM_TOSERVER) ? 0 : 1].filestore_cnt += file_no_match;
40,500✔
189
}
40,500✔
190

191
static bool StoreFilestoreSigsCantMatch(const SigGroupHead *sgh, const DetectEngineState *de_state, uint8_t direction)
192
{
40,500✔
193
    if (de_state->dir_state[(direction & STREAM_TOSERVER) ? 0 : 1].filestore_cnt ==
40,500✔
194
            sgh->filestore_cnt)
40,500✔
195
        return true;
31,258✔
196
    else
9,242✔
197
        return false;
9,242✔
198
}
40,500✔
199

200
static void StoreStateTxHandleFiles(const SigGroupHead *sgh, Flow *f, DetectEngineState *destate,
201
        const uint8_t flow_flags, void *tx, const uint64_t tx_id, const uint16_t file_no_match)
202
{
40,500✔
203
    SCLogDebug("tx %"PRIu64", file_no_match %u", tx_id, file_no_match);
40,500✔
204
    StoreFileNoMatchCnt(destate, file_no_match, flow_flags);
40,500✔
205
    if (StoreFilestoreSigsCantMatch(sgh, destate, flow_flags)) {
40,500✔
206
        SCLogDebug("filestore sigs can't match");
31,258✔
207
        FileDisableStoringForTransaction(
31,258✔
208
                f, flow_flags & (STREAM_TOCLIENT | STREAM_TOSERVER), tx, tx_id);
31,258✔
209
    } else {
31,258✔
210
        SCLogDebug("filestore sigs can still match");
9,242✔
211
    }
9,242✔
212
}
40,500✔
213

214
void DetectRunStoreStateTx(
215
        const SigGroupHead *sgh,
216
        Flow *f, void *tx, uint64_t tx_id,
217
        const Signature *s,
218
        uint32_t inspect_flags, uint8_t flow_flags,
219
        const uint16_t file_no_match)
220
{
40,500✔
221
    AppLayerTxData *tx_data = AppLayerParserGetTxData(f->proto, f->alproto, tx);
40,500✔
222
    if (tx_data->de_state == NULL) {
40,500✔
223
        tx_data->de_state = DetectEngineStateAlloc();
19,244✔
224
        if (tx_data->de_state == NULL)
19,244✔
225
            return;
×
226
        SCLogDebug("destate created for %"PRIu64, tx_id);
19,244✔
227
    }
19,244✔
228
    DeStateSignatureAppend(tx_data->de_state, s, inspect_flags, flow_flags);
40,500✔
229
    if (s->flags & SIG_FLAG_TXBOTHDIR) {
40,500✔
230
        // add also in the other DetectEngineStateDirection
231
        DeStateSignatureAppend(tx_data->de_state, s, inspect_flags,
13✔
232
                flow_flags ^ (STREAM_TOSERVER | STREAM_TOCLIENT));
13✔
233
    }
13✔
234
    StoreStateTxHandleFiles(sgh, f, tx_data->de_state, flow_flags, tx, tx_id, file_no_match);
40,500✔
235

236
    SCLogDebug("Stored for TX %"PRIu64, tx_id);
40,500✔
237
}
40,500✔
238

239
static inline void ResetTxState(DetectEngineState *s)
240
{
569✔
241
    if (s) {
569✔
UNCOV
242
        s->dir_state[0].cnt = 0;
×
UNCOV
243
        s->dir_state[0].filestore_cnt = 0;
×
UNCOV
244
        s->dir_state[0].flags = 0;
×
245
        /* reset 'cur' back to the list head */
UNCOV
246
        s->dir_state[0].cur = s->dir_state[0].head;
×
247

UNCOV
248
        s->dir_state[1].cnt = 0;
×
UNCOV
249
        s->dir_state[1].filestore_cnt = 0;
×
UNCOV
250
        s->dir_state[1].flags = 0;
×
251
        /* reset 'cur' back to the list head */
UNCOV
252
        s->dir_state[1].cur = s->dir_state[1].head;
×
UNCOV
253
    }
×
254
}
569✔
255

256
/** \brief Reset de state for active tx'
257
 *  To be used on detect engine reload.
258
 *  \param f write LOCKED flow
259
 */
260
void DetectEngineStateResetTxs(Flow *f)
261
{
1,482✔
262
    void *alstate = FlowGetAppState(f);
1,482✔
263
    if (!StateIsValid(f->alproto, alstate)) {
1,482✔
264
        return;
183✔
265
    }
183✔
266

267
    uint64_t inspect_ts = AppLayerParserGetTransactionInspectId(f->alparser, STREAM_TOCLIENT);
1,299✔
268
    uint64_t inspect_tc = AppLayerParserGetTransactionInspectId(f->alparser, STREAM_TOSERVER);
1,299✔
269

270
    uint64_t inspect_tx_id = MIN(inspect_ts, inspect_tc);
1,299✔
271

272
    uint64_t total_txs = AppLayerParserGetTxCnt(f, alstate);
1,299✔
273

274
    for ( ; inspect_tx_id < total_txs; inspect_tx_id++) {
1,868✔
275
        void *inspect_tx = AppLayerParserGetTx(f->proto, f->alproto, alstate, inspect_tx_id);
569✔
276
        if (inspect_tx != NULL) {
569✔
277
            AppLayerTxData *txd = AppLayerParserGetTxData(f->proto, f->alproto, inspect_tx);
569✔
278
            ResetTxState(txd->de_state);
569✔
279
        }
569✔
280
    }
569✔
281
}
1,299✔
282

283
/*********Unittests*********/
284

285
#ifdef UNITTESTS
286
#include "detect-engine-alert.h"
287

288
static int DeStateTest01(void)
289
{
290
    SCLogDebug("sizeof(DetectEngineState)\t\t%"PRIuMAX,
291
            (uintmax_t)sizeof(DetectEngineState));
292
    SCLogDebug("sizeof(DeStateStore)\t\t\t%"PRIuMAX,
293
            (uintmax_t)sizeof(DeStateStore));
294
    SCLogDebug("sizeof(DeStateStoreItem)\t\t%"PRIuMAX"",
295
            (uintmax_t)sizeof(DeStateStoreItem));
296

297
    return 1;
298
}
299

300
static int DeStateTest02(void)
301
{
302
    uint8_t direction = STREAM_TOSERVER;
303
    DetectEngineState *state = DetectEngineStateAlloc();
304
    FAIL_IF_NULL(state);
305
    FAIL_IF_NOT_NULL(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head);
306

307
    Signature s;
308
    memset(&s, 0x00, sizeof(s));
309

310
    s.iid = 0;
311
    DeStateSignatureAppend(state, &s, 0, direction);
312
    s.iid = 11;
313
    DeStateSignatureAppend(state, &s, 0, direction);
314
    s.iid = 22;
315
    DeStateSignatureAppend(state, &s, 0, direction);
316
    s.iid = 33;
317
    DeStateSignatureAppend(state, &s, 0, direction);
318
    s.iid = 44;
319
    DeStateSignatureAppend(state, &s, 0, direction);
320
    s.iid = 55;
321
    DeStateSignatureAppend(state, &s, 0, direction);
322
    s.iid = 66;
323
    DeStateSignatureAppend(state, &s, 0, direction);
324
    s.iid = 77;
325
    DeStateSignatureAppend(state, &s, 0, direction);
326
    s.iid = 88;
327
    DeStateSignatureAppend(state, &s, 0, direction);
328
    s.iid = 99;
329
    DeStateSignatureAppend(state, &s, 0, direction);
330
    s.iid = 100;
331
    DeStateSignatureAppend(state, &s, 0, direction);
332
    s.iid = 111;
333
    DeStateSignatureAppend(state, &s, 0, direction);
334
    s.iid = 122;
335
    DeStateSignatureAppend(state, &s, 0, direction);
336
    s.iid = 133;
337
    DeStateSignatureAppend(state, &s, 0, direction);
338
    FAIL_IF_NOT(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head ==
339
                state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur);
340

341
    s.iid = 144;
342
    DeStateSignatureAppend(state, &s, 0, direction);
343

344
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[14].sid != 144);
345
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head ==
346
            state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur);
347
    FAIL_IF_NOT(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur == NULL);
348

349
    s.iid = 155;
350
    DeStateSignatureAppend(state, &s, 0, direction);
351

352
    FAIL_IF_NOT(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].tail ==
353
                state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur);
354

355
    s.iid = 166;
356
    DeStateSignatureAppend(state, &s, 0, direction);
357

358
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL);
359
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].sid != 11);
360
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->next == NULL);
361
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[14].sid != 144);
362
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->next->store[0].sid != 155);
363
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->next->store[1].sid != 166);
364

365
    ResetTxState(state);
366

367
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL);
368
    FAIL_IF_NOT(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head ==
369
                state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur);
370

371
    s.iid = 0;
372
    DeStateSignatureAppend(state, &s, 0, direction);
373
    s.iid = 11;
374
    DeStateSignatureAppend(state, &s, 0, direction);
375
    s.iid = 22;
376
    DeStateSignatureAppend(state, &s, 0, direction);
377
    s.iid = 33;
378
    DeStateSignatureAppend(state, &s, 0, direction);
379
    s.iid = 44;
380
    DeStateSignatureAppend(state, &s, 0, direction);
381
    s.iid = 55;
382
    DeStateSignatureAppend(state, &s, 0, direction);
383
    s.iid = 66;
384
    DeStateSignatureAppend(state, &s, 0, direction);
385
    s.iid = 77;
386
    DeStateSignatureAppend(state, &s, 0, direction);
387
    s.iid = 88;
388
    DeStateSignatureAppend(state, &s, 0, direction);
389
    s.iid = 99;
390
    DeStateSignatureAppend(state, &s, 0, direction);
391
    s.iid = 100;
392
    DeStateSignatureAppend(state, &s, 0, direction);
393
    s.iid = 111;
394
    DeStateSignatureAppend(state, &s, 0, direction);
395
    s.iid = 122;
396
    DeStateSignatureAppend(state, &s, 0, direction);
397
    s.iid = 133;
398
    DeStateSignatureAppend(state, &s, 0, direction);
399
    FAIL_IF_NOT(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head ==
400
                state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur);
401
    s.iid = 144;
402
    DeStateSignatureAppend(state, &s, 0, direction);
403
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[14].sid != 144);
404
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head ==
405
            state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur);
406
    FAIL_IF_NOT(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].tail ==
407
                state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].cur);
408
    s.iid = 155;
409
    DeStateSignatureAppend(state, &s, 0, direction);
410
    s.iid = 166;
411
    DeStateSignatureAppend(state, &s, 0, direction);
412

413
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL);
414
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].sid != 11);
415
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->next == NULL);
416
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[14].sid != 144);
417
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->next->store[0].sid != 155);
418
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->next->store[1].sid != 166);
419

420
    SCDetectEngineStateFree(state);
421

422
    PASS;
423
}
424

425
static int DeStateTest03(void)
426
{
427
    DetectEngineState *state = DetectEngineStateAlloc();
428
    FAIL_IF_NULL(state);
429

430
    Signature s;
431
    memset(&s, 0x00, sizeof(s));
432

433
    uint8_t direction = STREAM_TOSERVER;
434

435
    s.iid = 11;
436
    DeStateSignatureAppend(state, &s, 0, direction);
437
    s.iid = 22;
438
    DeStateSignatureAppend(state, &s, BIT_U32(DE_STATE_FLAG_BASE), direction);
439

440
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL);
441
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].sid != 11);
442
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].flags & BIT_U32(DE_STATE_FLAG_BASE));
443
    FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].sid != 22);
444
    FAIL_IF(!(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].flags & BIT_U32(DE_STATE_FLAG_BASE)));
445

446
    SCDetectEngineStateFree(state);
447
    PASS;
448
}
449

450
static int DeStateSigTest01(void)
451
{
452
    DetectEngineThreadCtx *det_ctx = NULL;
453
    ThreadVars th_v;
454
    Flow f;
455
    TcpSession ssn;
456
    Packet *p = NULL;
457
    uint8_t httpbuf1[] = "POST / HTTP/1.0\r\n";
458
    uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\n";
459
    uint8_t httpbuf3[] = "Cookie: dummy\r\nContent-Length: 10\r\n\r\n";
460
    uint8_t httpbuf4[] = "Http Body!";
461
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
462
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
463
    uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
464
    uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
465

466
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
467
    FAIL_IF_NULL(alp_tctx);
468

469
    memset(&th_v, 0, sizeof(th_v));
470
    StatsThreadInit(&th_v.stats);
471
    memset(&f, 0, sizeof(f));
472
    memset(&ssn, 0, sizeof(ssn));
473

474
    p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
475
    FAIL_IF_NULL(p);
476

477
    FLOW_INITIALIZE(&f);
478
    f.protoctx = (void *)&ssn;
479
    f.proto = IPPROTO_TCP;
480
    f.flags |= FLOW_IPV4;
481
    f.alproto = ALPROTO_HTTP1;
482

483
    p->flow = &f;
484
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
485
    p->flowflags |= FLOW_PKT_TOSERVER;
486
    p->flowflags |= FLOW_PKT_ESTABLISHED;
487

488
    StreamTcpInitConfig(true);
489

490
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
491
    FAIL_IF_NULL(de_ctx);
492
    de_ctx->flags |= DE_QUIET;
493

494
    Signature *s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"dummy\"; http_cookie; sid:1; rev:1;)");
495
    FAIL_IF_NULL(s);
496

497
    SigGroupBuild(de_ctx);
498
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
499
    FAIL_IF_NULL(det_ctx);
500

501
    int r = AppLayerParserParse(
502
            NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
503
    FAIL_IF_NOT(r == 0);
504
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
505
    FAIL_IF(PacketAlertCheck(p, 1));
506

507
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
508
    FAIL_IF_NOT(r == 0);
509
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
510
    FAIL_IF(PacketAlertCheck(p, 1));
511

512
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
513
    FAIL_IF_NOT(r == 0);
514
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
515
    FAIL_IF_NOT(PacketAlertCheck(p, 1));
516

517
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf4, httplen4);
518
    FAIL_IF_NOT(r == 0);
519
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
520
    FAIL_IF(PacketAlertCheck(p, 1));
521

522
    UTHFreePacket(p);
523
    FLOW_DESTROY(&f);
524
    AppLayerParserThreadCtxFree(alp_tctx);
525
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
526
    DetectEngineCtxFree(de_ctx);
527
    StreamTcpFreeConfig(true);
528
    StatsThreadCleanup(&th_v.stats);
529
    PASS;
530
}
531

532
/** \test multiple pipelined http transactions */
533
static int DeStateSigTest02(void)
534
{
535
    DetectEngineThreadCtx *det_ctx = NULL;
536
    ThreadVars th_v;
537
    Flow f;
538
    TcpSession ssn;
539
    Packet *p = NULL;
540
    uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
541
    uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
542
    uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
543
    uint8_t httpbuf4[] = "Http Body!";
544
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
545
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
546
    uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
547
    uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
548
    uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
549
    uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
550
    uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nHttp Body!";
551
    uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
552
    uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
553
    uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
554
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
555
    FAIL_IF_NULL(alp_tctx);
556

557
    memset(&th_v, 0, sizeof(th_v));
558
    StatsThreadInit(&th_v.stats);
559
    memset(&f, 0, sizeof(f));
560
    memset(&ssn, 0, sizeof(ssn));
561

562
    p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
563

564
    FLOW_INITIALIZE(&f);
565
    f.protoctx = (void *)&ssn;
566
    f.proto = IPPROTO_TCP;
567
    f.flags |= FLOW_IPV4;
568

569
    p->flow = &f;
570
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
571
    p->flowflags |= FLOW_PKT_TOSERVER;
572
    p->flowflags |= FLOW_PKT_ESTABLISHED;
573
    f.alproto = ALPROTO_HTTP1;
574

575
    StreamTcpInitConfig(true);
576

577
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
578
    FAIL_IF_NULL(de_ctx);
579

580
    de_ctx->flags |= DE_QUIET;
581

582
    Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:to_server; content:\"POST\"; http_method; content:\"/\"; http_uri; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"body\"; nocase; http_client_body; sid:1; rev:1;)");
583
    FAIL_IF_NULL(s);
584
    s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (flow:to_server; content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; sid:2; rev:1;)");
585
    FAIL_IF_NULL(s);
586

587
    SigGroupBuild(de_ctx);
588
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
589
    FAIL_IF_NULL(det_ctx);
590

591
    int r = AppLayerParserParse(
592
            NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf1, httplen1);
593
    FAIL_IF(r != 0);
594
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
595
    FAIL_IF(PacketAlertCheck(p, 1));
596

597
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
598
    FAIL_IF(r != 0);
599
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
600
    FAIL_IF(PacketAlertCheck(p, 1));
601

602
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
603
    FAIL_IF(r != 0);
604
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
605
    FAIL_IF(PacketAlertCheck(p, 1));
606

607
    void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f.alstate, 0);
608
    FAIL_IF_NULL(tx);
609

610
    AppLayerTxData *tx_data = AppLayerParserGetTxData(IPPROTO_TCP, ALPROTO_HTTP1, tx);
611
    FAIL_IF_NULL(tx_data);
612
    DetectEngineState *tx_de_state = tx_data->de_state;
613
    FAIL_IF_NULL(tx_de_state);
614
    FAIL_IF(tx_de_state->dir_state[0].cnt != 1);
615
    /* http_header(mpm): 5, uri: 3, method: 6, cookie: 7 */
616
    uint32_t expected_flags = (BIT_U32(5) | BIT_U32(3) | BIT_U32(6) | BIT_U32(4));
617
    FAIL_IF(tx_de_state->dir_state[0].head->store[0].flags != expected_flags);
618

619
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf4, httplen4);
620
    FAIL_IF(r != 0);
621
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
622
    FAIL_IF(!(PacketAlertCheck(p, 1)));
623

624
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf5, httplen5);
625
    FAIL_IF(r != 0);
626
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
627
    FAIL_IF(PacketAlertCheck(p, 1));
628

629
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf6, httplen6);
630
    FAIL_IF(r != 0);
631
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
632
    FAIL_IF((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2)));
633

634
    r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf7, httplen7);
635
    FAIL_IF(r != 0);
636
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
637
    FAIL_IF(!(PacketAlertCheck(p, 2)));
638

639
    UTHFreePacket(p);
640
    FLOW_DESTROY(&f);
641
    AppLayerParserThreadCtxFree(alp_tctx);
642
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
643
    DetectEngineCtxFree(de_ctx);
644
    StreamTcpFreeConfig(true);
645
    StatsThreadCleanup(&th_v.stats);
646
    PASS;
647
}
648

649
static int DeStateSigTest03(void)
650
{
651
    uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
652
                         "Host: www.server.lan\r\n"
653
                         "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
654
                         "Content-Length: 215\r\n"
655
                         "\r\n"
656
                         "-----------------------------277531038314945\r\n"
657
                         "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
658
                         "Content-Type: image/jpeg\r\n"
659
                         "\r\n"
660
                         "filecontent\r\n"
661
                         "-----------------------------277531038314945--";
662
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
663
    ThreadVars th_v;
664
    TcpSession ssn;
665
    Flow *f = NULL;
666
    Packet *p = NULL;
667
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
668
    FAIL_IF_NULL(alp_tctx);
669

670
    memset(&th_v, 0, sizeof(th_v));
671
    StatsThreadInit(&th_v.stats);
672
    memset(&ssn, 0, sizeof(ssn));
673

674
    DetectEngineThreadCtx *det_ctx = NULL;
675
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
676
    FAIL_IF_NULL(de_ctx);
677

678
    de_ctx->flags |= DE_QUIET;
679

680
    Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (flow:to_server; content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)");
681
    FAIL_IF_NULL(s);
682

683
    SigGroupBuild(de_ctx);
684
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
685

686
    f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
687
    FAIL_IF_NULL(f);
688
    f->protoctx = &ssn;
689
    f->proto = IPPROTO_TCP;
690
    f->alproto = ALPROTO_HTTP1;
691

692
    p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
693
    FAIL_IF_NULL(p);
694

695
    p->flow = f;
696
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
697
    p->flowflags |= FLOW_PKT_TOSERVER;
698
    p->flowflags |= FLOW_PKT_ESTABLISHED;
699

700
    StreamTcpInitConfig(true);
701

702
    int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1,
703
            STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
704
    FAIL_IF(r != 0);
705

706
    HtpState *http_state = f->alstate;
707
    FAIL_IF_NULL(http_state);
708
    void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
709
    FAIL_IF_NULL(tx);
710
    HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
711
    FAIL_IF_NULL(tx_ud);
712

713
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
714
    FAIL_IF(!(PacketAlertCheck(p, 1)));
715

716
    AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
717
    FileContainer *fc = files.fc;
718
    FAIL_IF_NULL(fc);
719

720
    File *file = fc->head;
721
    FAIL_IF_NULL(file);
722

723
    FAIL_IF(!(file->flags & FILE_STORE));
724

725
    UTHFreePacket(p);
726
    UTHFreeFlow(f);
727

728
    AppLayerParserThreadCtxFree(alp_tctx);
729
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
730
    DetectEngineCtxFree(de_ctx);
731
    StreamTcpFreeConfig(true);
732
    StatsThreadCleanup(&th_v.stats);
733
    PASS;
734
}
735

736
static int DeStateSigTest04(void)
737
{
738
    uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
739
                         "Host: www.server.lan\r\n"
740
                         "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
741
                         "Content-Length: 215\r\n"
742
                         "\r\n"
743
                         "-----------------------------277531038314945\r\n"
744
                         "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
745
                         "Content-Type: image/jpeg\r\n"
746
                         "\r\n"
747
                         "filecontent\r\n"
748
                         "-----------------------------277531038314945--";
749
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
750
    ThreadVars th_v;
751
    TcpSession ssn;
752
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
753
    FAIL_IF_NULL(alp_tctx);
754

755
    memset(&th_v, 0, sizeof(th_v));
756
    StatsThreadInit(&th_v.stats);
757
    memset(&ssn, 0, sizeof(ssn));
758

759
    DetectEngineThreadCtx *det_ctx = NULL;
760
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
761
    FAIL_IF_NULL(de_ctx);
762
    de_ctx->flags |= DE_QUIET;
763

764
    Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"GET\"; http_method; content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)");
765
    FAIL_IF_NULL(s);
766

767
    SigGroupBuild(de_ctx);
768
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
769
    FAIL_IF_NULL(det_ctx);
770

771
    Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
772
    FAIL_IF_NULL(f);
773
    f->protoctx = &ssn;
774
    f->proto = IPPROTO_TCP;
775
    f->alproto = ALPROTO_HTTP1;
776

777
    Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
778
    FAIL_IF_NULL(p);
779
    p->flow = f;
780
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
781
    p->flowflags |= FLOW_PKT_TOSERVER;
782
    p->flowflags |= FLOW_PKT_ESTABLISHED;
783

784
    StreamTcpInitConfig(true);
785

786
    int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1,
787
            STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
788
    FAIL_IF(r != 0);
789
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
790
    FAIL_IF(PacketAlertCheck(p, 1));
791

792
    HtpState *http_state = f->alstate;
793
    FAIL_IF_NULL(http_state);
794
    void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
795
    FAIL_IF_NULL(tx);
796
    HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
797
    FAIL_IF_NULL(tx_ud);
798

799
    AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
800
    FileContainer *fc = files.fc;
801
    FAIL_IF_NULL(fc);
802
    File *file = fc->head;
803
    FAIL_IF_NULL(file);
804

805
    FAIL_IF(file->flags & FILE_STORE);
806

807
    UTHFreePacket(p);
808
    UTHFreeFlow(f);
809
    AppLayerParserThreadCtxFree(alp_tctx);
810
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
811
    DetectEngineCtxFree(de_ctx);
812
    StreamTcpFreeConfig(true);
813
    StatsThreadCleanup(&th_v.stats);
814
    PASS;
815
}
816

817
static int DeStateSigTest05(void)
818
{
819
    uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
820
                         "Host: www.server.lan\r\n"
821
                         "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
822
                         "Content-Length: 215\r\n"
823
                         "\r\n"
824
                         "-----------------------------277531038314945\r\n"
825
                         "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
826
                         "Content-Type: image/jpeg\r\n"
827
                         "\r\n"
828
                         "filecontent\r\n"
829
                         "-----------------------------277531038314945--";
830
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
831
    ThreadVars th_v;
832
    TcpSession ssn;
833

834
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
835
    FAIL_IF_NULL(alp_tctx);
836

837
    memset(&th_v, 0, sizeof(th_v));
838
    StatsThreadInit(&th_v.stats);
839
    memset(&ssn, 0, sizeof(ssn));
840

841
    DetectEngineThreadCtx *det_ctx = NULL;
842
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
843
    FAIL_IF_NULL(de_ctx);
844
    de_ctx->flags |= DE_QUIET;
845

846
    Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"GET\"; http_method; content:\"upload.cgi\"; http_uri; filename:\"nomatch\"; sid:1; rev:1;)");
847
    FAIL_IF_NULL(s);
848

849
    SigGroupBuild(de_ctx);
850
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
851

852
    Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
853
    FAIL_IF_NULL(f);
854
    f->protoctx = &ssn;
855
    f->proto = IPPROTO_TCP;
856
    f->alproto = ALPROTO_HTTP1;
857

858
    Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
859
    FAIL_IF_NULL(p);
860
    p->flow = f;
861
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
862
    p->flowflags |= FLOW_PKT_TOSERVER;
863
    p->flowflags |= FLOW_PKT_ESTABLISHED;
864

865
    StreamTcpInitConfig(true);
866

867
    int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1,
868
            STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
869
    FAIL_IF_NOT(r == 0);
870
    HtpState *http_state = f->alstate;
871
    FAIL_IF_NULL(http_state);
872
    void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
873
    FAIL_IF_NULL(tx);
874
    HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
875
    FAIL_IF_NULL(tx_ud);
876

877
    AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
878
    FileContainer *fc = files.fc;
879
    FAIL_IF_NULL(fc);
880
    File *file = fc->head;
881
    FAIL_IF_NULL(file);
882
    FAIL_IF(http_state->state_data.file_flags & FLOWFILE_NO_STORE_TS);
883

884
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
885
    FAIL_IF(PacketAlertCheck(p, 1));
886

887
    /* detect will have set FLOWFILE_NO_STORE_TS, but it won't have had
888
     * an opportunity to be applied to the file itself yet */
889
    FAIL_IF_NOT(http_state->state_data.file_flags & FLOWFILE_NO_STORE_TS);
890
    FAIL_IF(file->flags & FILE_NOSTORE);
891

892
    UTHFreePacket(p);
893
    UTHFreeFlow(f);
894
    AppLayerParserThreadCtxFree(alp_tctx);
895
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
896
    DetectEngineCtxFree(de_ctx);
897
    StreamTcpFreeConfig(true);
898
    StatsThreadCleanup(&th_v.stats);
899
    PASS;
900
}
901

902
static int DeStateSigTest06(void)
903
{
904
    uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
905
                         "Host: www.server.lan\r\n"
906
                         "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
907
                         "Content-Length: 215\r\n"
908
                         "\r\n"
909
                         "-----------------------------277531038314945\r\n"
910
                         "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
911
                         "Content-Type: image/jpeg\r\n"
912
                         "\r\n"
913
                         "filecontent\r\n"
914
                         "-----------------------------277531038314945--";
915
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
916
    ThreadVars th_v;
917
    TcpSession ssn;
918

919
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
920
    FAIL_IF_NULL(alp_tctx);
921

922
    memset(&th_v, 0, sizeof(th_v));
923
    StatsThreadInit(&th_v.stats);
924
    memset(&ssn, 0, sizeof(ssn));
925

926
    DetectEngineThreadCtx *det_ctx = NULL;
927
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
928
    FAIL_IF_NULL(de_ctx);
929
    de_ctx->flags |= DE_QUIET;
930

931
    Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filename:\"nomatch\"; filestore; sid:1; rev:1;)");
932
    FAIL_IF_NULL(s);
933

934
    SigGroupBuild(de_ctx);
935
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
936
    FAIL_IF_NULL(det_ctx);
937

938
    Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
939
    FAIL_IF_NULL(f);
940
    f->protoctx = &ssn;
941
    f->proto = IPPROTO_TCP;
942
    f->alproto = ALPROTO_HTTP1;
943

944
    Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
945
    FAIL_IF_NULL(p);
946
    p->flow = f;
947
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
948
    p->flowflags |= FLOW_PKT_TOSERVER;
949
    p->flowflags |= FLOW_PKT_ESTABLISHED;
950

951
    StreamTcpInitConfig(true);
952

953
    int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1,
954
            STREAM_TOSERVER | STREAM_START | STREAM_EOF, httpbuf1, httplen1);
955
    FAIL_IF(r != 0);
956
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
957
    FAIL_IF(PacketAlertCheck(p, 1));
958

959
    HtpState *http_state = f->alstate;
960
    FAIL_IF_NULL(http_state);
961
    void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
962
    FAIL_IF_NULL(tx);
963
    HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
964
    FAIL_IF_NULL(tx_ud);
965

966
    AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
967
    FileContainer *fc = files.fc;
968
    FAIL_IF_NULL(fc);
969
    File *file = fc->head;
970
    FAIL_IF_NULL(file);
971
    /* detect will have set FLOWFILE_NO_STORE_TS, but it won't have had
972
     * an opportunity to be applied to the file itself yet */
973
    FAIL_IF_NOT(tx_ud->tx_data.file_flags & FLOWFILE_NO_STORE_TS);
974
    FAIL_IF(file->flags & FILE_NOSTORE);
975

976
    UTHFreePacket(p);
977
    UTHFreeFlow(f);
978
    AppLayerParserThreadCtxFree(alp_tctx);
979
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
980
    DetectEngineCtxFree(de_ctx);
981
    StreamTcpFreeConfig(true);
982
    StatsThreadCleanup(&th_v.stats);
983
    PASS;
984
}
985

986
static int DeStateSigTest07(void)
987
{
988
    uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
989
                         "Host: www.server.lan\r\n"
990
                         "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
991
                         "Content-Length: 215\r\n"
992
                         "\r\n"
993
                         "-----------------------------277531038314945\r\n"
994
                         "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
995
                         "Content-Type: image/jpeg\r\n"
996
                         "\r\n";
997

998
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
999
    uint8_t httpbuf2[] = "filecontent\r\n"
1000
                         "-----------------------------277531038314945--";
1001
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1002
    ThreadVars th_v;
1003
    TcpSession ssn;
1004

1005
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1006
    FAIL_IF_NULL(alp_tctx);
1007

1008
    memset(&th_v, 0, sizeof(th_v));
1009
    StatsThreadInit(&th_v.stats);
1010
    memset(&ssn, 0, sizeof(ssn));
1011

1012
    DetectEngineThreadCtx *det_ctx = NULL;
1013
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1014
    FAIL_IF_NULL(de_ctx);
1015
    de_ctx->flags |= DE_QUIET;
1016

1017
    Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"GET\"; http_method; content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)");
1018
    FAIL_IF_NULL(s);
1019

1020
    SigGroupBuild(de_ctx);
1021
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1022

1023
    Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1024
    FAIL_IF_NULL(f);
1025
    f->protoctx = &ssn;
1026
    f->proto = IPPROTO_TCP;
1027
    f->alproto = ALPROTO_HTTP1;
1028

1029
    Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1030
    FAIL_IF_NULL(p);
1031
    p->flow = f;
1032
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1033
    p->flowflags |= FLOW_PKT_TOSERVER;
1034
    p->flowflags |= FLOW_PKT_ESTABLISHED;
1035

1036
    StreamTcpInitConfig(true);
1037

1038
    int r = AppLayerParserParse(
1039
            NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1040
    FAIL_IF(r != 0);
1041
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1042
    FAIL_IF(PacketAlertCheck(p, 1));
1043

1044
    r = AppLayerParserParse(
1045
            NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2);
1046
    FAIL_IF(r != 0);
1047
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1048
    FAIL_IF(PacketAlertCheck(p, 1));
1049

1050
    HtpState *http_state = f->alstate;
1051
    FAIL_IF_NULL(http_state);
1052
    void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1053
    FAIL_IF_NULL(tx);
1054
    HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1055
    FAIL_IF_NULL(tx_ud);
1056

1057
    AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
1058
    FileContainer *fc = files.fc;
1059
    FAIL_IF_NULL(fc);
1060
    File *file = fc->head;
1061
    FAIL_IF_NULL(file);
1062
    FAIL_IF(file->flags & FILE_STORE);
1063

1064
    UTHFreePacket(p);
1065
    UTHFreeFlow(f);
1066
    AppLayerParserThreadCtxFree(alp_tctx);
1067
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1068
    DetectEngineCtxFree(de_ctx);
1069
    StreamTcpFreeConfig(true);
1070
    StatsThreadCleanup(&th_v.stats);
1071
    PASS;
1072
}
1073

1074
/**
1075
 * \test multiple files in a tx
1076
 */
1077
static int DeStateSigTest08(void)
1078
{
1079
    uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1080
                         "Host: www.server.lan\r\n"
1081
                         "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1082
                         "Content-Length: 440\r\n"
1083
                         "\r\n"
1084
                         "-----------------------------277531038314945\r\n"
1085
                         "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"AAAApicture1.jpg\"\r\n"
1086
                         "Content-Type: image/jpeg\r\n"
1087
                         "\r\n";
1088

1089
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1090
    uint8_t httpbuf2[] = "file";
1091
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1092
    uint8_t httpbuf3[] = "content\r\n"
1093
                         "-----------------------------277531038314945\r\n";
1094
    uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1095

1096
    uint8_t httpbuf4[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"BBBBpicture2.jpg\"\r\n"
1097
                         "Content-Type: image/jpeg\r\n"
1098
                         "\r\n"
1099
                         "filecontent2\r\n"
1100
                         "-----------------------------277531038314945--";
1101
    uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1102

1103
    ThreadVars th_v;
1104
    TcpSession ssn;
1105

1106
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1107
    FAIL_IF_NULL(alp_tctx);
1108

1109
    memset(&th_v, 0, sizeof(th_v));
1110
    StatsThreadInit(&th_v.stats);
1111
    memset(&ssn, 0, sizeof(ssn));
1112

1113
    DetectEngineThreadCtx *det_ctx = NULL;
1114
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1115
    FAIL_IF_NULL(de_ctx);
1116
    de_ctx->flags |= DE_QUIET;
1117

1118
    Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filename:\"BBBBpicture\"; filestore; sid:1; rev:1;)");
1119
    FAIL_IF_NULL(s);
1120

1121
    SigGroupBuild(de_ctx);
1122
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1123

1124
    Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1125
    FAIL_IF_NULL(f);
1126
    f->protoctx = &ssn;
1127
    f->proto = IPPROTO_TCP;
1128
    f->alproto = ALPROTO_HTTP1;
1129

1130
    Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1131
    FAIL_IF_NULL(p);
1132
    p->flow = f;
1133
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1134
    p->flowflags |= FLOW_PKT_TOSERVER;
1135
    p->flowflags |= FLOW_PKT_ESTABLISHED;
1136

1137
    StreamTcpInitConfig(true);
1138

1139
    /* HTTP request with 1st part of the multipart body */
1140

1141
    int r = AppLayerParserParse(
1142
            NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1143
    FAIL_IF(r != 0);
1144
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1145
    FAIL_IF(PacketAlertCheck(p, 1));
1146

1147
    r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1148
    FAIL_IF(r != 0);
1149
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1150
    FAIL_IF(PacketAlertCheck(p, 1));
1151

1152
    HtpState *http_state = f->alstate;
1153
    FAIL_IF_NULL(http_state);
1154
    void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1155
    FAIL_IF_NULL(tx);
1156
    HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1157
    FAIL_IF_NULL(tx_ud);
1158

1159
    AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
1160
    FileContainer *fc = files.fc;
1161
    FAIL_IF_NULL(fc);
1162
    File *file = fc->head;
1163
    FAIL_IF_NULL(file);
1164
    FAIL_IF(file->flags & FILE_STORE);
1165

1166
    /* 2nd multipart body file */
1167

1168
    r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
1169
    FAIL_IF(r != 0);
1170
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1171
    FAIL_IF(PacketAlertCheck(p, 1));
1172

1173
    r = AppLayerParserParse(
1174
            NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1175
    FAIL_IF(r != 0);
1176
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1177
    FAIL_IF_NOT(PacketAlertCheck(p, 1));
1178

1179
    http_state = f->alstate;
1180
    FAIL_IF_NULL(http_state);
1181
    tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1182
    FAIL_IF_NULL(tx);
1183
    tx_ud = htp_tx_get_user_data(tx);
1184
    FAIL_IF_NULL(tx_ud);
1185

1186
    files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
1187
    fc = files.fc;
1188
    FAIL_IF_NULL(fc);
1189
    file = fc->head;
1190
    FAIL_IF_NULL(file);
1191
    file = file->next;
1192
    FAIL_IF_NULL(file);
1193
    FAIL_IF_NOT(file->flags & FILE_STORE);
1194

1195
    UTHFreePacket(p);
1196
    UTHFreeFlow(f);
1197
    AppLayerParserThreadCtxFree(alp_tctx);
1198
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1199
    DetectEngineCtxFree(de_ctx);
1200
    StreamTcpFreeConfig(true);
1201
    StatsThreadCleanup(&th_v.stats);
1202
    PASS;
1203
}
1204

1205
/**
1206
 * \test multiple files in a tx. Both files should match
1207
 */
1208
static int DeStateSigTest09(void)
1209
{
1210
    uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1211
                         "Host: www.server.lan\r\n"
1212
                         "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1213
                         "Content-Length: 440\r\n"
1214
                         "\r\n"
1215
                         "-----------------------------277531038314945\r\n"
1216
                         "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1217
                         "Content-Type: image/jpeg\r\n"
1218
                         "\r\n";
1219

1220
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1221
    uint8_t httpbuf2[] = "file";
1222
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1223
    uint8_t httpbuf3[] = "content\r\n"
1224
                         "-----------------------------277531038314945\r\n";
1225
    uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1226

1227
    uint8_t httpbuf4[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
1228
                         "Content-Type: image/jpeg\r\n"
1229
                         "\r\n"
1230
                         "filecontent2\r\n"
1231
                         "-----------------------------277531038314945--";
1232
    uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1233

1234
    ThreadVars th_v;
1235
    TcpSession ssn;
1236

1237
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1238
    FAIL_IF_NULL(alp_tctx);
1239

1240
    memset(&th_v, 0, sizeof(th_v));
1241
    StatsThreadInit(&th_v.stats);
1242
    memset(&ssn, 0, sizeof(ssn));
1243

1244
    DetectEngineThreadCtx *det_ctx = NULL;
1245
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1246
    FAIL_IF_NULL(de_ctx);
1247
    de_ctx->flags |= DE_QUIET;
1248

1249
    Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filename:\"somepicture\"; filestore; sid:1; rev:1;)");
1250
    FAIL_IF_NULL(s);
1251

1252
    SigGroupBuild(de_ctx);
1253
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1254

1255
    Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1256
    FAIL_IF_NULL(f);
1257
    f->protoctx = &ssn;
1258
    f->proto = IPPROTO_TCP;
1259
    f->alproto = ALPROTO_HTTP1;
1260

1261
    Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1262
    FAIL_IF_NULL(p);
1263
    p->flow = f;
1264
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1265
    p->flowflags |= FLOW_PKT_TOSERVER;
1266
    p->flowflags |= FLOW_PKT_ESTABLISHED;
1267

1268
    StreamTcpInitConfig(true);
1269

1270
    /* HTTP request with 1st part of the multipart body */
1271

1272
    int r = AppLayerParserParse(
1273
            NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1274
    FAIL_IF(r != 0);
1275
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1276
    FAIL_IF_NOT(PacketAlertCheck(p, 1));
1277

1278
    r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1279
    FAIL_IF(r != 0);
1280
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1281
    FAIL_IF(PacketAlertCheck(p, 1));
1282

1283
    HtpState *http_state = f->alstate;
1284
    FAIL_IF_NULL(http_state);
1285
    void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1286
    FAIL_IF_NULL(tx);
1287
    HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1288
    FAIL_IF_NULL(tx_ud);
1289

1290
    AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
1291
    FileContainer *fc = files.fc;
1292
    FAIL_IF_NULL(fc);
1293
    File *file = fc->head;
1294
    FAIL_IF_NULL(file);
1295
    FAIL_IF_NOT(file->flags & FILE_STORE);
1296

1297
    /* 2nd multipart body file */
1298

1299
    r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
1300
    FAIL_IF(r != 0);
1301
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1302
    FAIL_IF(PacketAlertCheck(p, 1));
1303

1304
    r = AppLayerParserParse(
1305
            NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1306
    FAIL_IF(r != 0);
1307
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1308
    FAIL_IF_NOT(PacketAlertCheck(p, 1));
1309

1310
    http_state = f->alstate;
1311
    FAIL_IF_NULL(http_state);
1312
    tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1313
    FAIL_IF_NULL(tx);
1314
    tx_ud = htp_tx_get_user_data(tx);
1315
    FAIL_IF_NULL(tx_ud);
1316

1317
    files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
1318
    fc = files.fc;
1319
    FAIL_IF_NULL(fc);
1320
    file = fc->head;
1321
    FAIL_IF_NULL(file);
1322
    FAIL_IF_NOT(file->flags & FILE_STORE);
1323

1324
    UTHFreePacket(p);
1325
    UTHFreeFlow(f);
1326
    AppLayerParserThreadCtxFree(alp_tctx);
1327
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1328
    DetectEngineCtxFree(de_ctx);
1329
    StreamTcpFreeConfig(true);
1330
    StatsThreadCleanup(&th_v.stats);
1331
    PASS;
1332
}
1333

1334
/**
1335
 * \test multiple files in a tx. Both files should match. No other matches.
1336
 */
1337
static int DeStateSigTest10(void)
1338
{
1339
    uint8_t httpbuf1[] = "POST /upload.cgi HTTP/1.1\r\n"
1340
                         "Host: www.server.lan\r\n"
1341
                         "Content-Type: multipart/form-data; boundary=---------------------------277531038314945\r\n"
1342
                         "Content-Length: 440\r\n"
1343
                         "\r\n"
1344
                         "-----------------------------277531038314945\r\n"
1345
                         "Content-Disposition: form-data; name=\"uploadfile_0\"; filename=\"somepicture1.jpg\"\r\n"
1346
                         "Content-Type: image/jpeg\r\n"
1347
                         "\r\n";
1348

1349
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
1350
    uint8_t httpbuf2[] = "file";
1351
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
1352
    uint8_t httpbuf3[] = "content\r\n"
1353
                         "-----------------------------277531038314945\r\n";
1354
    uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
1355

1356
    uint8_t httpbuf4[] = "Content-Disposition: form-data; name=\"uploadfile_1\"; filename=\"somepicture2.jpg\"\r\n"
1357
                         "Content-Type: image/jpeg\r\n"
1358
                         "\r\n"
1359
                         "filecontent2\r\n"
1360
                         "-----------------------------277531038314945--";
1361
    uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
1362

1363
    ThreadVars th_v;
1364
    TcpSession ssn;
1365

1366
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
1367
    FAIL_IF_NULL(alp_tctx);
1368

1369
    memset(&th_v, 0, sizeof(th_v));
1370
    StatsThreadInit(&th_v.stats);
1371
    memset(&ssn, 0, sizeof(ssn));
1372

1373
    DetectEngineThreadCtx *det_ctx = NULL;
1374
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1375
    FAIL_IF_NULL(de_ctx);
1376
    de_ctx->flags |= DE_QUIET;
1377

1378
    Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (filename:\"somepicture\"; filestore; sid:1; rev:1;)");
1379
    FAIL_IF_NULL(s);
1380

1381
    SigGroupBuild(de_ctx);
1382
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1383

1384
    Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
1385
    FAIL_IF_NULL(f);
1386
    f->protoctx = &ssn;
1387
    f->proto = IPPROTO_TCP;
1388
    f->alproto = ALPROTO_HTTP1;
1389

1390
    Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1391
    FAIL_IF_NULL(p);
1392
    p->flow = f;
1393
    p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
1394
    p->flowflags |= FLOW_PKT_TOSERVER;
1395
    p->flowflags |= FLOW_PKT_ESTABLISHED;
1396

1397
    StreamTcpInitConfig(true);
1398

1399
    /* HTTP request with 1st part of the multipart body */
1400

1401
    int r = AppLayerParserParse(
1402
            NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_START, httpbuf1, httplen1);
1403
    FAIL_IF(r != 0);
1404
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1405
    FAIL_IF_NOT(PacketAlertCheck(p, 1));
1406

1407
    r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf2, httplen2);
1408
    FAIL_IF(r != 0);
1409
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1410
    FAIL_IF(PacketAlertCheck(p, 1));
1411

1412
    HtpState *http_state = f->alstate;
1413
    FAIL_IF_NULL(http_state);
1414
    void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1415
    FAIL_IF_NULL(tx);
1416
    HtpTxUserData *tx_ud = htp_tx_get_user_data(tx);
1417
    FAIL_IF_NULL(tx_ud);
1418

1419
    AppLayerGetFileState files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
1420
    FileContainer *fc = files.fc;
1421
    FAIL_IF_NULL(fc);
1422
    File *file = fc->head;
1423
    FAIL_IF_NULL(file);
1424
    FAIL_IF_NOT(file->flags & FILE_STORE);
1425

1426
    /* 2nd multipart body file */
1427

1428
    r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, httpbuf3, httplen3);
1429
    FAIL_IF(r != 0);
1430
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1431
    FAIL_IF(PacketAlertCheck(p, 1));
1432

1433
    r = AppLayerParserParse(
1434
            NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4);
1435
    FAIL_IF(r != 0);
1436
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1437
    FAIL_IF_NOT(PacketAlertCheck(p, 1));
1438

1439
    http_state = f->alstate;
1440
    FAIL_IF_NULL(http_state);
1441
    tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP1, f->alstate, 0);
1442
    FAIL_IF_NULL(tx);
1443
    tx_ud = htp_tx_get_user_data(tx);
1444
    FAIL_IF_NULL(tx_ud);
1445

1446
    files = AppLayerParserGetTxFiles(p->flow, tx, STREAM_TOSERVER);
1447
    fc = files.fc;
1448
    FAIL_IF_NULL(fc);
1449
    file = fc->head;
1450
    FAIL_IF_NULL(file);
1451
    FAIL_IF_NOT(file->flags & FILE_STORE);
1452

1453
    UTHFreePacket(p);
1454
    UTHFreeFlow(f);
1455
    AppLayerParserThreadCtxFree(alp_tctx);
1456
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1457
    DetectEngineCtxFree(de_ctx);
1458
    StreamTcpFreeConfig(true);
1459
    StatsThreadCleanup(&th_v.stats);
1460
    PASS;
1461
}
1462

1463
#endif
1464

1465
void DeStateRegisterTests(void)
UNCOV
1466
{
×
1467
#ifdef UNITTESTS
1468
    UtRegisterTest("DeStateTest01", DeStateTest01);
1469
    UtRegisterTest("DeStateTest02", DeStateTest02);
1470
    UtRegisterTest("DeStateTest03", DeStateTest03);
1471
    UtRegisterTest("DeStateSigTest01", DeStateSigTest01);
1472
    UtRegisterTest("DeStateSigTest02", DeStateSigTest02);
1473
    UtRegisterTest("DeStateSigTest03", DeStateSigTest03);
1474
    UtRegisterTest("DeStateSigTest04", DeStateSigTest04);
1475
    UtRegisterTest("DeStateSigTest05", DeStateSigTest05);
1476
    UtRegisterTest("DeStateSigTest06", DeStateSigTest06);
1477
    UtRegisterTest("DeStateSigTest07", DeStateSigTest07);
1478
    UtRegisterTest("DeStateSigTest08", DeStateSigTest08);
1479
    UtRegisterTest("DeStateSigTest09", DeStateSigTest09);
1480
    UtRegisterTest("DeStateSigTest10", DeStateSigTest10);
1481
#endif
UNCOV
1482
}
×
1483

1484
/**
1485
 * @}
1486
 */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc