Coverage Report

Created: 2026-08-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/stream-tcp-reassemble.c
Line
Count
Source
1
/* Copyright (C) 2007-2024 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 Gurvinder Singh <gurvindersinghdahiya@gmail.com>
22
 * \author Victor Julien <victor@inliniac.net>
23
 *
24
 * Reference:
25
 * Judy Novak, Steve Sturges: Target-Based TCP Stream Reassembly August, 2007
26
 *
27
 */
28
29
#include "suricata-common.h"
30
#include "suricata.h"
31
#include "packet.h"
32
#include "detect.h"
33
#include "flow.h"
34
#include "threads.h"
35
#include "conf.h"
36
#include "action-globals.h"
37
38
#include "flow-util.h"
39
40
#include "threadvars.h"
41
#include "tm-threads.h"
42
43
#include "util-pool.h"
44
#include "util-unittest.h"
45
#include "util-print.h"
46
#include "util-host-os-info.h"
47
#include "util-unittest-helper.h"
48
#include "util-byte.h"
49
#include "util-device.h"
50
51
#include "stream-tcp.h"
52
#include "stream-tcp-private.h"
53
#include "stream-tcp-cache.h"
54
#include "stream-tcp-reassemble.h"
55
#include "stream-tcp-inline.h"
56
#include "stream-tcp-list.h"
57
#include "stream-tcp-util.h"
58
59
#include "stream.h"
60
61
#include "util-debug.h"
62
#include "app-layer-protos.h"
63
#include "app-layer.h"
64
#include "app-layer-events.h"
65
#include "app-layer-parser.h"
66
#include "app-layer-frames.h"
67
68
#include "detect-engine-state.h"
69
70
#include "util-profiling.h"
71
#include "util-validate.h"
72
#include "util-exception-policy.h"
73
74
#ifdef DEBUG
75
static SCMutex segment_pool_memuse_mutex;
76
static uint64_t segment_pool_memuse = 0;
77
static uint64_t segment_pool_memcnt = 0;
78
#endif
79
80
thread_local uint64_t t_pcapcnt = UINT64_MAX;
81
82
PoolThread *segment_thread_pool = NULL;
83
/* init only, protect initializing and growing pool */
84
static SCMutex segment_thread_pool_mutex = SCMUTEX_INITIALIZER;
85
86
/* Memory use counter */
87
SC_ATOMIC_DECLARE(uint64_t, ra_memuse);
88
89
static int g_tcp_session_dump_enabled = 0;
90
91
inline bool IsTcpSessionDumpingEnabled(void)
92
12.0M
{
93
12.0M
    return g_tcp_session_dump_enabled == 1;
94
12.0M
}
95
96
void EnableTcpSessionDumping(void)
97
0
{
98
0
    g_tcp_session_dump_enabled = 1;
99
0
}
100
101
/* prototypes */
102
TcpSegment *StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *);
103
void StreamTcpCreateTestPacket(uint8_t *, uint8_t, uint8_t, uint8_t);
104
105
void StreamTcpReassembleInitMemuse(void)
106
73
{
107
73
    SC_ATOMIC_INIT(ra_memuse);
108
73
}
109
110
/**
111
 *  \brief  Function to Increment the memory usage counter for the TCP reassembly
112
 *          segments
113
 *
114
 *  \param  size Size of the TCP segment and its payload length memory allocated
115
 */
116
void StreamTcpReassembleIncrMemuse(uint64_t size)
117
1.69M
{
118
1.69M
    (void) SC_ATOMIC_ADD(ra_memuse, size);
119
1.69M
    SCLogDebug("REASSEMBLY %"PRIu64", incr %"PRIu64, StreamTcpReassembleMemuseGlobalCounter(), size);
120
1.69M
    return;
121
1.69M
}
122
123
/**
124
 *  \brief  Function to Decrease the memory usage counter for the TCP reassembly
125
 *          segments
126
 *
127
 *  \param  size Size of the TCP segment and its payload length memory allocated
128
 */
129
void StreamTcpReassembleDecrMemuse(uint64_t size)
130
1.57M
{
131
#ifdef UNITTESTS
132
    uint64_t presize = SC_ATOMIC_GET(ra_memuse);
133
    if (RunmodeIsUnittests()) {
134
        BUG_ON(presize > UINT_MAX);
135
    }
136
#endif
137
138
1.57M
    (void) SC_ATOMIC_SUB(ra_memuse, size);
139
140
#ifdef UNITTESTS
141
    if (RunmodeIsUnittests()) {
142
        uint64_t postsize = SC_ATOMIC_GET(ra_memuse);
143
        BUG_ON(postsize > presize);
144
    }
145
#endif
146
1.57M
    SCLogDebug("REASSEMBLY %"PRIu64", decr %"PRIu64, StreamTcpReassembleMemuseGlobalCounter(), size);
147
1.57M
    return;
148
1.57M
}
149
150
uint64_t StreamTcpReassembleMemuseGlobalCounter(void)
151
0
{
152
0
    uint64_t smemuse = SC_ATOMIC_GET(ra_memuse);
153
0
    return smemuse;
154
0
}
155
156
/**
157
 * \brief  Function to Check the reassembly memory usage counter against the
158
 *         allowed max memory usage for TCP segments.
159
 *
160
 * \param  size Size of the TCP segment and its payload length memory allocated
161
 * \retval 1 if in bounds
162
 * \retval 0 if not in bounds
163
 */
164
int StreamTcpReassembleCheckMemcap(uint64_t size)
165
4.64M
{
166
#ifdef QA_SIMULATION
167
    if (unlikely((g_eps_stream_reassembly_memcap != UINT64_MAX &&
168
                  g_eps_stream_reassembly_memcap == t_pcapcnt))) {
169
        SCLogNotice("simulating memcap reached condition for packet %" PRIu64, t_pcapcnt);
170
        return 0;
171
    }
172
#endif
173
4.64M
    uint64_t memcapcopy = SC_ATOMIC_GET(stream_config.reassembly_memcap);
174
4.64M
    if (memcapcopy == 0 ||
175
4.64M
        (uint64_t)((uint64_t)size + SC_ATOMIC_GET(ra_memuse)) <= memcapcopy)
176
4.64M
        return 1;
177
0
    return 0;
178
4.64M
}
179
180
/**
181
 *  \brief Update memcap value
182
 *
183
 *  \param size new memcap value
184
 */
185
int StreamTcpReassembleSetMemcap(uint64_t size)
186
0
{
187
0
    if (size == 0 || (uint64_t)SC_ATOMIC_GET(ra_memuse) < size) {
188
0
        SC_ATOMIC_SET(stream_config.reassembly_memcap, size);
189
0
        return 1;
190
0
    }
191
192
0
    return 0;
193
0
}
194
195
/**
196
 *  \brief Return memcap value
197
 *
198
 *  \return memcap memcap value
199
 */
200
uint64_t StreamTcpReassembleGetMemcap(void)
201
0
{
202
0
    uint64_t memcapcopy = SC_ATOMIC_GET(stream_config.reassembly_memcap);
203
0
    return memcapcopy;
204
0
}
205
206
/* memory functions for the streaming buffer API */
207
208
/*
209
    void *(*Calloc)(size_t n, size_t size);
210
*/
211
static void *ReassembleCalloc(size_t n, size_t size)
212
1.58M
{
213
1.58M
    if (StreamTcpReassembleCheckMemcap(n * size) == 0) {
214
0
        sc_errno = SC_ELIMIT;
215
0
        return NULL;
216
0
    }
217
1.58M
    void *ptr = SCCalloc(n, size);
218
1.58M
    if (ptr == NULL) {
219
0
        sc_errno = SC_ENOMEM;
220
0
        return NULL;
221
0
    }
222
1.58M
    StreamTcpReassembleIncrMemuse(n * size);
223
1.58M
    return ptr;
224
1.58M
}
225
226
/*
227
    void *(*Realloc)(void *ptr, size_t orig_size, size_t size);
228
*/
229
void *StreamTcpReassembleRealloc(void *optr, size_t orig_size, size_t size)
230
289k
{
231
289k
    if (size > orig_size) {
232
286k
        if (StreamTcpReassembleCheckMemcap(size - orig_size) == 0) {
233
0
            SCLogDebug("memcap hit at %" PRIu64, SC_ATOMIC_GET(stream_config.reassembly_memcap));
234
0
            sc_errno = SC_ELIMIT;
235
0
            return NULL;
236
0
        }
237
286k
    }
238
289k
    void *nptr = SCRealloc(optr, size);
239
289k
    if (nptr == NULL) {
240
0
        SCLogDebug("realloc fail");
241
0
        sc_errno = SC_ENOMEM;
242
0
        return NULL;
243
0
    }
244
289k
    if (size > orig_size) {
245
286k
        StreamTcpReassembleIncrMemuse(size - orig_size);
246
286k
    } else {
247
2.62k
        StreamTcpReassembleDecrMemuse(orig_size - size);
248
2.62k
    }
249
289k
    return nptr;
250
289k
}
251
252
/*
253
    void (*Free)(void *ptr, size_t size);
254
*/
255
static void ReassembleFree(void *ptr, size_t size)
256
1.58M
{
257
1.58M
    SCFree(ptr);
258
1.58M
    StreamTcpReassembleDecrMemuse(size);
259
1.58M
}
260
261
/** \brief alloc a tcp segment pool entry */
262
static void *TcpSegmentPoolAlloc(void)
263
784k
{
264
784k
    SCLogDebug("segment alloc");
265
784k
    if (StreamTcpReassembleCheckMemcap((uint32_t)sizeof(TcpSegment)) == 0) {
266
0
        return NULL;
267
0
    }
268
269
784k
    TcpSegment *seg = NULL;
270
271
784k
    seg = SCMalloc(sizeof (TcpSegment));
272
784k
    if (unlikely(seg == NULL))
273
0
        return NULL;
274
275
784k
    if (IsTcpSessionDumpingEnabled()) {
276
0
        uint32_t memuse =
277
0
                sizeof(TcpSegmentPcapHdrStorage) + sizeof(uint8_t) * TCPSEG_PKT_HDR_DEFAULT_SIZE;
278
0
        if (StreamTcpReassembleCheckMemcap(sizeof(TcpSegment) + memuse) == 0) {
279
0
            SCFree(seg);
280
0
            return NULL;
281
0
        }
282
283
0
        seg->pcap_hdr_storage = SCCalloc(1, sizeof(TcpSegmentPcapHdrStorage));
284
0
        if (seg->pcap_hdr_storage == NULL) {
285
0
            SCLogError("Unable to allocate memory for "
286
0
                       "TcpSegmentPcapHdrStorage");
287
0
            SCFree(seg);
288
0
            return NULL;
289
0
        } else {
290
0
            seg->pcap_hdr_storage->alloclen = sizeof(uint8_t) * TCPSEG_PKT_HDR_DEFAULT_SIZE;
291
0
            seg->pcap_hdr_storage->pkt_hdr =
292
0
                    SCCalloc(1, sizeof(uint8_t) * TCPSEG_PKT_HDR_DEFAULT_SIZE);
293
0
            if (seg->pcap_hdr_storage->pkt_hdr == NULL) {
294
0
                SCLogError("Unable to allocate memory for "
295
0
                           "packet header data within "
296
0
                           "TcpSegmentPcapHdrStorage");
297
0
                SCFree(seg->pcap_hdr_storage);
298
0
                SCFree(seg);
299
0
                return NULL;
300
0
            }
301
0
        }
302
303
0
        StreamTcpReassembleIncrMemuse(memuse);
304
784k
    } else {
305
784k
        seg->pcap_hdr_storage = NULL;
306
784k
    }
307
308
784k
    return seg;
309
784k
}
310
311
static int TcpSegmentPoolInit(void *data, void *initdata)
312
1.38M
{
313
1.38M
    TcpSegment *seg = (TcpSegment *) data;
314
1.38M
    TcpSegmentPcapHdrStorage *pcap_hdr;
315
316
1.38M
    pcap_hdr = seg->pcap_hdr_storage;
317
318
    /* do this before the can bail, so TcpSegmentPoolCleanup
319
     * won't have uninitialized memory to consider. */
320
1.38M
    memset(seg, 0, sizeof (TcpSegment));
321
322
1.38M
    if (IsTcpSessionDumpingEnabled()) {
323
0
        uint32_t memuse =
324
0
                sizeof(TcpSegmentPcapHdrStorage) + sizeof(char) * TCPSEG_PKT_HDR_DEFAULT_SIZE;
325
0
        seg->pcap_hdr_storage = pcap_hdr;
326
0
        if (StreamTcpReassembleCheckMemcap(sizeof(TcpSegment) + memuse) == 0) {
327
0
            return 0;
328
0
        }
329
0
        StreamTcpReassembleIncrMemuse(memuse);
330
1.38M
    } else {
331
1.38M
        if (StreamTcpReassembleCheckMemcap((uint32_t)sizeof(TcpSegment)) == 0) {
332
0
            return 0;
333
0
        }
334
1.38M
    }
335
336
#ifdef DEBUG
337
    SCMutexLock(&segment_pool_memuse_mutex);
338
    segment_pool_memuse += sizeof(TcpSegment);
339
    segment_pool_memcnt++;
340
    SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt);
341
    SCMutexUnlock(&segment_pool_memuse_mutex);
342
#endif
343
344
1.38M
    StreamTcpReassembleIncrMemuse((uint32_t)sizeof(TcpSegment));
345
1.38M
    return 1;
346
1.38M
}
347
348
/** \brief clean up a tcp segment pool entry */
349
static void TcpSegmentPoolCleanup(void *ptr)
350
779k
{
351
779k
    if (ptr == NULL)
352
0
        return;
353
354
779k
    TcpSegment *seg = (TcpSegment *)ptr;
355
779k
    if (seg && seg->pcap_hdr_storage) {
356
0
        if (seg->pcap_hdr_storage->pkt_hdr) {
357
0
            SCFree(seg->pcap_hdr_storage->pkt_hdr);
358
0
            StreamTcpReassembleDecrMemuse(seg->pcap_hdr_storage->alloclen);
359
0
        }
360
0
        SCFree(seg->pcap_hdr_storage);
361
0
        seg->pcap_hdr_storage = NULL;
362
0
        StreamTcpReassembleDecrMemuse((uint32_t)sizeof(TcpSegmentPcapHdrStorage));
363
0
    }
364
365
779k
    StreamTcpReassembleDecrMemuse((uint32_t)sizeof(TcpSegment));
366
367
#ifdef DEBUG
368
    SCMutexLock(&segment_pool_memuse_mutex);
369
    segment_pool_memuse -= sizeof(TcpSegment);
370
    segment_pool_memcnt--;
371
    SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt);
372
    SCMutexUnlock(&segment_pool_memuse_mutex);
373
#endif
374
779k
}
375
376
/**
377
 *  \brief Function to return the segment back to the pool.
378
 *
379
 *  \param seg Segment which will be returned back to the pool.
380
 */
381
void StreamTcpSegmentReturntoPool(TcpSegment *seg)
382
9.25M
{
383
9.25M
    if (seg == NULL)
384
0
        return;
385
386
9.25M
    if (seg->pcap_hdr_storage && seg->pcap_hdr_storage->pktlen) {
387
0
        seg->pcap_hdr_storage->pktlen = 0;
388
0
    }
389
390
9.25M
    StreamTcpThreadCacheReturnSegment(seg);
391
9.25M
}
392
393
/**
394
 *  \brief return all segments in this stream into the pool(s)
395
 *
396
 *  \param stream the stream to cleanup
397
 */
398
void StreamTcpReturnStreamSegments (TcpStream *stream)
399
994k
{
400
994k
    TcpSegment *seg = NULL, *safe = NULL;
401
994k
    RB_FOREACH_SAFE(seg, TCPSEG, &stream->seg_tree, safe)
402
5.03M
    {
403
5.03M
        RB_REMOVE(TCPSEG, &stream->seg_tree, seg);
404
5.03M
        StreamTcpSegmentReturntoPool(seg);
405
5.03M
    }
406
994k
}
407
408
static inline uint64_t GetAbsLastAck(const TcpStream *stream)
409
13.3M
{
410
13.3M
    if (STREAM_LASTACK_GT_BASESEQ(stream)) {
411
12.7M
        return STREAM_BASE_OFFSET(stream) + (stream->last_ack - stream->base_seq);
412
12.7M
    } else {
413
526k
        return STREAM_BASE_OFFSET(stream);
414
526k
    }
415
13.3M
}
416
417
uint64_t StreamTcpGetAcked(const TcpStream *stream)
418
0
{
419
0
    return GetAbsLastAck(stream);
420
0
}
421
422
// may contain gaps
423
uint64_t StreamDataRightEdge(const TcpStream *stream, const bool eof)
424
261k
{
425
261k
    uint64_t right_edge = STREAM_BASE_OFFSET(stream) + stream->segs_right_edge - stream->base_seq;
426
261k
    if (!eof && StreamTcpInlineMode() == FALSE) {
427
223k
        right_edge = MIN(GetAbsLastAck(stream), right_edge);
428
223k
    }
429
261k
    return right_edge;
430
261k
}
431
432
uint64_t StreamTcpGetUsable(const TcpStream *stream, const bool eof)
433
4.56M
{
434
4.56M
    uint64_t right_edge = StreamingBufferGetConsecutiveDataRightEdge(&stream->sb);
435
4.56M
    if (!eof && StreamTcpInlineMode() == FALSE) {
436
4.30M
        right_edge = MIN(GetAbsLastAck(stream), right_edge);
437
4.30M
    }
438
4.56M
    return right_edge;
439
4.56M
}
440
441
#ifdef UNITTESTS
442
/** \internal
443
 *  \brief check if segments falls before stream 'offset' */
444
static inline int SEGMENT_BEFORE_OFFSET(TcpStream *stream, TcpSegment *seg, uint64_t offset)
445
{
446
    if (seg->sbseg.stream_offset + seg->sbseg.segment_len <= offset)
447
        return 1;
448
    return 0;
449
}
450
#endif
451
452
/** \param f locked flow */
453
void StreamTcpDisableAppLayer(Flow *f)
454
210k
{
455
210k
    if (f->protoctx == NULL)
456
0
        return;
457
458
210k
    TcpSession *ssn = (TcpSession *)f->protoctx;
459
210k
    StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client);
460
210k
    StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server);
461
210k
    StreamTcpDisableAppLayerReassembly(ssn);
462
210k
    if (f->alparser) {
463
81.5k
        AppLayerParserStateSetFlag(f->alparser,
464
81.5k
                (APP_LAYER_PARSER_EOF_TS|APP_LAYER_PARSER_EOF_TC));
465
81.5k
    }
466
210k
}
467
468
/** \param f locked flow */
469
int StreamTcpAppLayerIsDisabled(Flow *f)
470
0
{
471
0
    if (f->protoctx == NULL || f->proto != IPPROTO_TCP)
472
0
        return 0;
473
474
0
    TcpSession *ssn = (TcpSession *)f->protoctx;
475
0
    return (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
476
0
}
477
478
static int StreamTcpReassemblyConfig(bool quiet)
479
33
{
480
33
    uint32_t segment_prealloc = 2048;
481
33
    ConfNode *seg = ConfGetNode("stream.reassembly.segment-prealloc");
482
33
    if (seg) {
483
0
        uint32_t prealloc = 0;
484
0
        if (StringParseUint32(&prealloc, 10, (uint16_t)strlen(seg->val), seg->val) < 0) {
485
0
            SCLogError("segment-prealloc of "
486
0
                       "%s is invalid",
487
0
                    seg->val);
488
0
            return -1;
489
0
        }
490
0
        segment_prealloc = prealloc;
491
0
    }
492
33
    if (!quiet)
493
33
        SCLogConfig("stream.reassembly \"segment-prealloc\": %u", segment_prealloc);
494
33
    stream_config.prealloc_segments = segment_prealloc;
495
496
33
    int overlap_diff_data = 0;
497
33
    (void)ConfGetBool("stream.reassembly.check-overlap-different-data", &overlap_diff_data);
498
33
    if (overlap_diff_data) {
499
0
        StreamTcpReassembleConfigEnableOverlapCheck();
500
0
    }
501
33
    if (StreamTcpInlineMode() == TRUE) {
502
0
        StreamTcpReassembleConfigEnableOverlapCheck();
503
0
    }
504
505
33
    uint16_t max_regions = 8;
506
33
    ConfNode *mr = ConfGetNode("stream.reassembly.max-regions");
507
33
    if (mr) {
508
0
        uint16_t max_r = 0;
509
0
        if (StringParseUint16(&max_r, 10, (uint16_t)strlen(mr->val), mr->val) < 0) {
510
0
            SCLogError("max-regions %s is invalid", mr->val);
511
0
            return -1;
512
0
        }
513
0
        max_regions = max_r;
514
0
    }
515
33
    if (!quiet)
516
33
        SCLogConfig("stream.reassembly \"max-regions\": %u", max_regions);
517
518
33
    stream_config.prealloc_segments = segment_prealloc;
519
33
    stream_config.sbcnf.buf_size = 2048;
520
33
    stream_config.sbcnf.max_regions = max_regions;
521
33
    stream_config.sbcnf.region_gap = STREAMING_BUFFER_REGION_GAP_DEFAULT;
522
33
    stream_config.sbcnf.Calloc = ReassembleCalloc;
523
33
    stream_config.sbcnf.Realloc = StreamTcpReassembleRealloc;
524
33
    stream_config.sbcnf.Free = ReassembleFree;
525
526
33
    return 0;
527
33
}
528
529
int StreamTcpReassembleInit(bool quiet)
530
73
{
531
    /* init the memcap/use tracker */
532
73
    StreamTcpReassembleInitMemuse();
533
534
73
    if (StreamTcpReassemblyConfig(quiet) < 0)
535
0
        return -1;
536
537
#ifdef DEBUG
538
    SCMutexInit(&segment_pool_memuse_mutex, NULL);
539
#endif
540
73
    StatsRegisterGlobalCounter("tcp.reassembly_memuse",
541
73
            StreamTcpReassembleMemuseGlobalCounter);
542
73
    return 0;
543
73
}
544
545
void StreamTcpReassembleFree(bool quiet)
546
0
{
547
0
    SCMutexLock(&segment_thread_pool_mutex);
548
0
    if (segment_thread_pool != NULL) {
549
0
        PoolThreadFree(segment_thread_pool);
550
0
        segment_thread_pool = NULL;
551
0
    }
552
0
    SCMutexUnlock(&segment_thread_pool_mutex);
553
0
    SCMutexDestroy(&segment_thread_pool_mutex);
554
555
#ifdef DEBUG
556
    if (segment_pool_memuse > 0)
557
        SCLogDebug("segment_pool_memuse %" PRIu64 " segment_pool_memcnt %" PRIu64 "",
558
                segment_pool_memuse, segment_pool_memcnt);
559
    SCMutexDestroy(&segment_pool_memuse_mutex);
560
#endif
561
0
}
562
563
TcpReassemblyThreadCtx *StreamTcpReassembleInitThreadCtx(ThreadVars *tv)
564
4
{
565
4
    SCEnter();
566
4
    TcpReassemblyThreadCtx *ra_ctx = SCMalloc(sizeof(TcpReassemblyThreadCtx));
567
4
    if (unlikely(ra_ctx == NULL))
568
0
        return NULL;
569
570
4
    memset(ra_ctx, 0x00, sizeof(TcpReassemblyThreadCtx));
571
572
4
    ra_ctx->app_tctx = AppLayerGetCtxThread(tv);
573
574
4
    SCMutexLock(&segment_thread_pool_mutex);
575
4
    if (segment_thread_pool == NULL) {
576
4
        segment_thread_pool = PoolThreadInit(1, /* thread */
577
4
                0, /* unlimited */
578
4
                stream_config.prealloc_segments,
579
4
                sizeof(TcpSegment),
580
4
                TcpSegmentPoolAlloc,
581
4
                TcpSegmentPoolInit, NULL,
582
4
                TcpSegmentPoolCleanup, NULL);
583
4
        ra_ctx->segment_thread_pool_id = 0;
584
4
        SCLogDebug("pool size %d, thread segment_thread_pool_id %d",
585
4
                PoolThreadSize(segment_thread_pool),
586
4
                ra_ctx->segment_thread_pool_id);
587
4
    } else {
588
        /* grow segment_thread_pool until we have an element for our thread id */
589
0
        ra_ctx->segment_thread_pool_id = PoolThreadExpand(segment_thread_pool);
590
0
        SCLogDebug("pool size %d, thread segment_thread_pool_id %d",
591
0
                PoolThreadSize(segment_thread_pool),
592
0
                ra_ctx->segment_thread_pool_id);
593
0
    }
594
4
    SCMutexUnlock(&segment_thread_pool_mutex);
595
4
    if (ra_ctx->segment_thread_pool_id < 0 || segment_thread_pool == NULL) {
596
0
        SCLogError("failed to setup/expand stream segment pool. Expand stream.reassembly.memcap?");
597
0
        StreamTcpReassembleFreeThreadCtx(ra_ctx);
598
0
        SCReturnPtr(NULL, "TcpReassemblyThreadCtx");
599
0
    }
600
601
4
    SCReturnPtr(ra_ctx, "TcpReassemblyThreadCtx");
602
4
}
603
604
void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *ra_ctx)
605
0
{
606
0
    SCEnter();
607
0
    StreamTcpThreadCacheCleanup();
608
609
0
    if (ra_ctx) {
610
0
        AppLayerDestroyCtxThread(ra_ctx->app_tctx);
611
0
        SCFree(ra_ctx);
612
0
    }
613
0
    SCReturn;
614
0
}
615
616
/**
617
 *  \brief check if stream in pkt direction has depth reached
618
 *
619
 *  \param p packet with *LOCKED* flow
620
 *
621
 *  \retval 1 stream has depth reached
622
 *  \retval 0 stream does not have depth reached
623
 */
624
int StreamTcpReassembleDepthReached(Packet *p)
625
24.9M
{
626
24.9M
    if (p->flow != NULL && p->flow->protoctx != NULL) {
627
24.9M
        TcpSession *ssn = p->flow->protoctx;
628
24.9M
        TcpStream *stream;
629
24.9M
        if (p->flowflags & FLOW_PKT_TOSERVER) {
630
12.4M
            stream = &ssn->client;
631
12.5M
        } else {
632
12.5M
            stream = &ssn->server;
633
12.5M
        }
634
635
24.9M
        return (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) ? 1 : 0;
636
24.9M
    }
637
638
11.4k
    return 0;
639
24.9M
}
640
641
/**
642
 *  \internal
643
 *  \brief Function to Check the reassembly depth valuer against the
644
 *        allowed max depth of the stream reassembly for TCP streams.
645
 *
646
 *  \param stream stream direction
647
 *  \param seq sequence number where "size" starts
648
 *  \param size size of the segment that is added
649
 *
650
 *  \retval size Part of the size that fits in the depth, 0 if none
651
 */
652
static uint32_t StreamTcpReassembleCheckDepth(TcpSession *ssn, TcpStream *stream,
653
        uint32_t seq, uint32_t size)
654
9.25M
{
655
9.25M
    SCEnter();
656
657
    /* if the configured depth value is 0, it means there is no limit on
658
       reassembly depth. Otherwise carry on my boy ;) */
659
9.25M
    if (ssn->reassembly_depth == 0) {
660
5.76M
        SCReturnUInt(size);
661
5.76M
    }
662
663
    /* if the final flag is set, we're not accepting anymore */
664
3.49M
    if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
665
0
        SCReturnUInt(0);
666
0
    }
667
668
3.49M
    uint64_t seg_depth;
669
3.49M
    if (SEQ_GT(stream->base_seq, seq)) {
670
7.48k
        if (SEQ_LEQ(seq+size, stream->base_seq)) {
671
1
            SCLogDebug("segment entirely before base_seq, weird: base %u, seq %u, re %u",
672
1
                    stream->base_seq, seq, seq+size);
673
1
            SCReturnUInt(0);
674
1
        }
675
676
7.48k
        seg_depth = STREAM_BASE_OFFSET(stream) + size - (stream->base_seq - seq);
677
3.48M
    } else {
678
3.48M
        seg_depth = STREAM_BASE_OFFSET(stream) + ((seq + size) - stream->base_seq);
679
3.48M
    }
680
681
    /* if the base_seq has moved passed the depth window we stop
682
     * checking and just reject the rest of the packets including
683
     * retransmissions. Saves us the hassle of dealing with sequence
684
     * wraps as well */
685
3.49M
    SCLogDebug("seq + size %u, base %u, seg_depth %"PRIu64" limit %u", (seq + size),
686
3.49M
            stream->base_seq, seg_depth,
687
3.49M
            ssn->reassembly_depth);
688
689
3.49M
    if (seg_depth > (uint64_t)ssn->reassembly_depth) {
690
4.12k
        SCLogDebug("STREAMTCP_STREAM_FLAG_DEPTH_REACHED");
691
4.12k
        stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED;
692
4.12k
        SCReturnUInt(0);
693
4.12k
    }
694
3.48M
    SCLogDebug("NOT STREAMTCP_STREAM_FLAG_DEPTH_REACHED");
695
3.48M
    SCLogDebug("%"PRIu64" <= %u", seg_depth, ssn->reassembly_depth);
696
#if 0
697
    SCLogDebug("full depth not yet reached: %"PRIu64" <= %"PRIu32,
698
            (stream->base_seq_offset + stream->base_seq + size),
699
            (stream->isn + ssn->reassembly_depth));
700
#endif
701
3.48M
    if (SEQ_GEQ(seq, stream->isn) && SEQ_LT(seq, (stream->isn + ssn->reassembly_depth))) {
702
        /* packet (partly?) fits the depth window */
703
704
3.48M
        if (SEQ_LEQ((seq + size),(stream->isn + 1 + ssn->reassembly_depth))) {
705
            /* complete fit */
706
3.48M
            SCReturnUInt(size);
707
3.48M
        } else {
708
0
            stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED;
709
            /* partial fit, return only what fits */
710
0
            uint32_t part = (stream->isn + 1 + ssn->reassembly_depth) - seq;
711
0
            DEBUG_VALIDATE_BUG_ON(part > size);
712
0
            if (part > size)
713
0
                part = size;
714
0
            SCReturnUInt(part);
715
0
        }
716
3.48M
    }
717
718
3.48M
    SCReturnUInt(0);
719
3.48M
}
720
721
uint32_t StreamDataAvailableForProtoDetect(TcpStream *stream)
722
397k
{
723
397k
    if (RB_EMPTY(&stream->sb.sbb_tree)) {
724
328k
        if (stream->sb.region.stream_offset != 0)
725
0
            return 0;
726
727
328k
        return stream->sb.region.buf_offset;
728
328k
    } else {
729
69.1k
        DEBUG_VALIDATE_BUG_ON(stream->sb.head == NULL);
730
69.1k
        DEBUG_VALIDATE_BUG_ON(stream->sb.sbb_size == 0);
731
69.1k
        return stream->sb.sbb_size;
732
69.1k
    }
733
397k
}
734
735
/**
736
 *  \brief Insert a packets TCP data into the stream reassembly engine.
737
 *
738
 *  \retval 0 good segment, as far as we checked.
739
 *  \retval -1 insert failure due to memcap
740
 *
741
 *  If the retval is 0 the segment is inserted correctly, or overlap is handled,
742
 *  or it wasn't added because of reassembly depth.
743
 *
744
 */
745
int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
746
                                TcpSession *ssn, TcpStream *stream, Packet *p)
747
5.27M
{
748
5.27M
    SCEnter();
749
750
5.27M
    if (ssn->data_first_seen_dir == 0) {
751
172k
        if (PKT_IS_TOSERVER(p)) {
752
147k
            ssn->data_first_seen_dir = STREAM_TOSERVER;
753
147k
        } else {
754
25.0k
            ssn->data_first_seen_dir = STREAM_TOCLIENT;
755
25.0k
        }
756
172k
    }
757
758
    /* If the OS policy is not set then set the OS policy for this stream */
759
5.27M
    if (stream->os_policy == 0) {
760
219k
        StreamTcpSetOSPolicy(stream, p);
761
219k
    }
762
763
5.27M
    if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) &&
764
124k
        (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED)) {
765
508
        SCLogDebug("ssn %p: both app and raw reassembly disabled, not reassembling", ssn);
766
508
        SCReturnInt(0);
767
508
    }
768
769
5.27M
    uint16_t *urg_offset;
770
5.27M
    if (PKT_IS_TOSERVER(p)) {
771
2.84M
        urg_offset = &ssn->urg_offset_ts;
772
2.84M
    } else {
773
2.43M
        urg_offset = &ssn->urg_offset_tc;
774
2.43M
    }
775
776
    /* segment sequence number, offset by previously accepted
777
     * URG OOB data. */
778
5.27M
    uint32_t seg_seq = TCP_GET_RAW_SEQ(p->tcph) - (*urg_offset);
779
5.27M
    uint8_t urg_data = 0;
780
781
    /* if stream_config.urgent_policy == TCP_STREAM_URGENT_DROP, we won't get here */
782
5.27M
    if (p->tcph->th_flags & TH_URG) {
783
118k
        const uint16_t urg_ptr = SCNtohs(p->tcph->th_urp);
784
118k
        if (urg_ptr > 0 && urg_ptr <= p->payload_len &&
785
47.4k
                (stream_config.urgent_policy == TCP_STREAM_URGENT_OOB ||
786
47.4k
                        stream_config.urgent_policy == TCP_STREAM_URGENT_GAP)) {
787
            /* track up to 64k out of band URG bytes. Fall back to inline
788
             * when that budget is exceeded. */
789
0
            if ((*urg_offset) < UINT16_MAX) {
790
0
                if (stream_config.urgent_policy == TCP_STREAM_URGENT_OOB)
791
0
                    (*urg_offset)++;
792
793
0
                if ((*urg_offset) == UINT16_MAX) {
794
0
                    StreamTcpSetEvent(p, STREAM_REASSEMBLY_URGENT_OOB_LIMIT_REACHED);
795
0
                }
796
0
            } else {
797
                /* OOB limit DROP is handled here */
798
0
                if (stream_config.urgent_oob_limit_policy == TCP_STREAM_URGENT_DROP) {
799
0
                    PacketDrop(p, ACTION_DROP, PKT_DROP_REASON_STREAM_URG);
800
0
                    SCReturnInt(0);
801
0
                }
802
0
            }
803
0
            urg_data = 1; /* only treat last 1 byte as out of band. */
804
0
            if (stream_config.urgent_policy == TCP_STREAM_URGENT_OOB) {
805
0
                StatsIncr(tv, ra_ctx->counter_tcp_urgent_oob);
806
0
            }
807
808
            /* depending on hitting the OOB limit, update urg_data or not */
809
0
            if (stream_config.urgent_policy == TCP_STREAM_URGENT_OOB &&
810
0
                    (*urg_offset) == UINT16_MAX &&
811
0
                    stream_config.urgent_oob_limit_policy == TCP_STREAM_URGENT_INLINE) {
812
0
                urg_data = 0;
813
0
            } else {
814
0
                if (urg_ptr == 1 && p->payload_len == 1) {
815
0
                    SCLogDebug("no non-URG data");
816
0
                    SCReturnInt(0);
817
0
                }
818
0
            }
819
0
        }
820
118k
    }
821
822
5.27M
    const uint16_t payload_len = p->payload_len - urg_data;
823
824
    /* If we have reached the defined depth for either of the stream, then stop
825
       reassembling the TCP session */
826
5.27M
    uint32_t size = StreamTcpReassembleCheckDepth(ssn, stream, seg_seq, payload_len);
827
5.27M
    SCLogDebug("ssn %p: check depth returned %"PRIu32, ssn, size);
828
829
5.27M
    if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
830
0
        StreamTcpSetEvent(p, STREAM_REASSEMBLY_DEPTH_REACHED);
831
        /* increment stream depth counter */
832
0
        StatsIncr(tv, ra_ctx->counter_tcp_stream_depth);
833
0
        p->app_update_direction = UPDATE_DIR_PACKET;
834
0
    }
835
5.27M
    if (size == 0) {
836
0
        SCLogDebug("ssn %p: depth reached, not reassembling", ssn);
837
0
        SCReturnInt(0);
838
0
    }
839
840
5.27M
    DEBUG_VALIDATE_BUG_ON(size > payload_len);
841
5.27M
    if (size > payload_len)
842
0
        size = payload_len;
843
844
5.27M
    TcpSegment *seg = StreamTcpGetSegment(tv, ra_ctx);
845
5.27M
    if (seg == NULL) {
846
0
        SCLogDebug("segment_pool is empty");
847
0
        StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
848
0
        ssn->flags |= STREAMTCP_FLAG_LOSSY_BE_LIBERAL;
849
0
        SCReturnInt(-1);
850
0
    }
851
852
5.27M
    DEBUG_VALIDATE_BUG_ON(size > UINT16_MAX);
853
5.27M
    TCP_SEG_LEN(seg) = (uint16_t)size;
854
    /* set SEQUENCE number, adjusted to any URG pointer offset */
855
5.27M
    seg->seq = seg_seq;
856
857
    /* HACK: for TFO SYN packets the seq for data starts at + 1 */
858
5.27M
    if (TCP_HAS_TFO(p) && p->payload_len && (p->tcph->th_flags & TH_SYN))
859
4.22k
        seg->seq += 1;
860
861
    /* proto detection skipped, but now we do get data. Set event. */
862
5.27M
    if (RB_EMPTY(&stream->seg_tree) &&
863
273k
        stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED) {
864
865
0
        AppLayerDecoderEventsSetEventRaw(&p->app_layer_events,
866
0
                APPLAYER_PROTO_DETECTION_SKIPPED);
867
0
    }
868
869
5.27M
    int r = StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, seg, p, p->payload, payload_len);
870
5.27M
    if (r < 0) {
871
0
        if (r == -SC_ENOMEM) {
872
0
            ssn->flags |= STREAMTCP_FLAG_LOSSY_BE_LIBERAL;
873
0
        }
874
0
        SCLogDebug("StreamTcpReassembleInsertSegment failed");
875
0
        SCReturnInt(-1);
876
0
    }
877
5.27M
    SCReturnInt(0);
878
5.27M
}
879
880
static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream,
881
                                      Packet *p)
882
15.6M
{
883
15.6M
    uint8_t flag = 0;
884
885
15.6M
    if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) {
886
2.74M
        flag |= STREAM_START;
887
2.74M
    }
888
889
15.6M
    if (ssn->state == TCP_CLOSED) {
890
246k
        flag |= STREAM_EOF;
891
246k
    }
892
893
15.6M
    if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
894
3.84M
        flag |= STREAM_MIDSTREAM;
895
3.84M
    }
896
897
15.6M
    if (p->flags & PKT_PSEUDO_STREAM_END) {
898
401k
        flag |= STREAM_EOF;
899
401k
    }
900
901
15.6M
    if (&ssn->client == stream) {
902
6.78M
        flag |= STREAM_TOSERVER;
903
8.86M
    } else {
904
8.86M
        flag |= STREAM_TOCLIENT;
905
8.86M
    }
906
15.6M
    if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
907
4.24k
        flag |= STREAM_DEPTH;
908
4.24k
    }
909
15.6M
    return flag;
910
15.6M
}
911
912
/**
913
 *  \brief Check the minimum size limits for reassembly.
914
 *
915
 *  \retval 0 don't reassemble yet
916
 *  \retval 1 do reassemble
917
 */
918
static int StreamTcpReassembleRawCheckLimit(const TcpSession *ssn,
919
        const TcpStream *stream, const Packet *p)
920
2.34M
{
921
2.34M
    SCEnter();
922
923
    /* if any of these flags is set we always inspect immediately */
924
2.34M
#define STREAMTCP_STREAM_FLAG_FLUSH_FLAGS       \
925
2.34M
        (   STREAMTCP_STREAM_FLAG_DEPTH_REACHED \
926
2.34M
        |   STREAMTCP_STREAM_FLAG_TRIGGER_RAW   \
927
2.34M
        |   STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED)
928
929
2.34M
    if (stream->flags & STREAMTCP_STREAM_FLAG_FLUSH_FLAGS) {
930
369k
        if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
931
739
            SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_DEPTH_REACHED "
932
739
                    "is set, so not expecting any new data segments");
933
739
        }
934
369k
        if (stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW) {
935
368k
            SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_TRIGGER_RAW is set");
936
368k
        }
937
369k
        if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) {
938
2.37k
            SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED is set, "
939
2.37k
                    "so no new segments will be considered");
940
2.37k
        }
941
369k
        SCReturnInt(1);
942
369k
    }
943
1.97M
#undef STREAMTCP_STREAM_FLAG_FLUSH_FLAGS
944
945
    /* some states mean we reassemble no matter how much data we have */
946
1.97M
    if (ssn->state > TCP_TIME_WAIT)
947
319k
        SCReturnInt(1);
948
949
1.65M
    if (p->flags & PKT_PSEUDO_STREAM_END)
950
38.9k
        SCReturnInt(1);
951
952
1.61M
    const uint64_t last_ack_abs = GetAbsLastAck(stream);
953
1.61M
    int64_t diff = last_ack_abs - STREAM_RAW_PROGRESS(stream);
954
1.61M
    int64_t chunk_size = PKT_IS_TOSERVER(p) ? (int64_t)stream_config.reassembly_toserver_chunk_size
955
1.61M
                                            : (int64_t)stream_config.reassembly_toclient_chunk_size;
956
957
    /* check if we have enough data to do raw reassembly */
958
1.61M
    if (chunk_size <= diff) {
959
149k
        SCReturnInt(1);
960
1.46M
    } else {
961
1.46M
        SCLogDebug("%s min chunk len not yet reached: "
962
1.46M
                   "last_ack %" PRIu32 ", ra_raw_base_seq %" PRIu32 ", %" PRIu32 " < "
963
1.46M
                   "%" PRIi64,
964
1.46M
                PKT_IS_TOSERVER(p) ? "toserver" : "toclient", stream->last_ack, stream->base_seq,
965
1.46M
                (stream->last_ack - stream->base_seq), chunk_size);
966
1.46M
        SCReturnInt(0);
967
1.46M
    }
968
969
1.61M
    SCReturnInt(0);
970
1.61M
}
971
972
/**
973
 *  \brief see what if any work the TCP session still needs
974
 */
975
uint8_t StreamNeedsReassembly(const TcpSession *ssn, uint8_t direction)
976
492k
{
977
492k
    const TcpStream *stream = NULL;
978
#ifdef DEBUG
979
    const char *dirstr = NULL;
980
#endif
981
492k
    if (direction == STREAM_TOSERVER) {
982
246k
        stream = &ssn->client;
983
#ifdef DEBUG
984
        dirstr = "client";
985
#endif
986
246k
    } else {
987
246k
        stream = &ssn->server;
988
#ifdef DEBUG
989
        dirstr = "server";
990
#endif
991
246k
    }
992
492k
    int use_app = 1;
993
492k
    int use_raw = 1;
994
995
492k
    if (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) {
996
        // app is dead
997
56.3k
        use_app = 0;
998
56.3k
    }
999
1000
492k
    if (stream->flags & STREAMTCP_STREAM_FLAG_DISABLE_RAW) {
1001
        // raw is dead
1002
341k
        use_raw = 0;
1003
341k
    }
1004
492k
    if (use_raw) {
1005
151k
        const uint64_t right_edge =
1006
151k
                STREAM_BASE_OFFSET(stream) + stream->segs_right_edge - stream->base_seq;
1007
151k
        SCLogDebug("%s: app %" PRIu64 " (use: %s), raw %" PRIu64
1008
151k
                   " (use: %s). Stream right edge: %" PRIu64,
1009
151k
                dirstr, STREAM_APP_PROGRESS(stream), use_app ? "yes" : "no",
1010
151k
                STREAM_RAW_PROGRESS(stream), use_raw ? "yes" : "no", right_edge);
1011
151k
        if (right_edge > STREAM_RAW_PROGRESS(stream)) {
1012
129k
            SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION", dirstr);
1013
129k
            return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
1014
129k
        }
1015
151k
    }
1016
362k
    if (use_app) {
1017
314k
        const uint64_t right_edge = StreamingBufferGetConsecutiveDataRightEdge(&stream->sb);
1018
314k
        SCLogDebug("%s: app %" PRIu64 " (use: %s), raw %" PRIu64
1019
314k
                   " (use: %s). Stream right edge: %" PRIu64,
1020
314k
                dirstr, STREAM_APP_PROGRESS(stream), use_app ? "yes" : "no",
1021
314k
                STREAM_RAW_PROGRESS(stream), use_raw ? "yes" : "no", right_edge);
1022
314k
        if (right_edge > STREAM_APP_PROGRESS(stream)) {
1023
67.2k
            SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION", dirstr);
1024
67.2k
            return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
1025
67.2k
        }
1026
314k
    }
1027
1028
295k
    SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NONE", dirstr);
1029
295k
    return STREAM_HAS_UNPROCESSED_SEGMENTS_NONE;
1030
362k
}
1031
1032
#ifdef DEBUG
1033
static uint64_t GetStreamSize(TcpStream *stream)
1034
{
1035
    if (stream) {
1036
        uint64_t size = 0;
1037
        uint32_t cnt = 0;
1038
        uint64_t last_ack_abs = GetAbsLastAck(stream);
1039
        uint64_t last_re = 0;
1040
1041
        SCLogDebug("stream_offset %" PRIu64, stream->sb.region.stream_offset);
1042
1043
        TcpSegment *seg;
1044
        RB_FOREACH(seg, TCPSEG, &stream->seg_tree) {
1045
            const uint64_t seg_abs =
1046
                    STREAM_BASE_OFFSET(stream) + (uint64_t)(seg->seq - stream->base_seq);
1047
            if (last_re != 0 && last_re < seg_abs) {
1048
                const char *gacked = NULL;
1049
                if (last_ack_abs >= seg_abs) {
1050
                    gacked = "fully ack'd";
1051
                } else if (last_ack_abs > last_re) {
1052
                    gacked = "partly ack'd";
1053
                } else {
1054
                    gacked = "not yet ack'd";
1055
                }
1056
                SCLogDebug(" -> gap of size %" PRIu64 ", ack:%s", seg_abs - last_re, gacked);
1057
            }
1058
1059
            const char *acked = NULL;
1060
            if (last_ack_abs >= seg_abs + (uint64_t)TCP_SEG_LEN(seg)) {
1061
                acked = "fully ack'd";
1062
            } else if (last_ack_abs > seg_abs) {
1063
                acked = "partly ack'd";
1064
            } else {
1065
                acked = "not yet ack'd";
1066
            }
1067
1068
            SCLogDebug("%u -> seg %p seq %u abs %" PRIu64 " size %u abs %" PRIu64 " (%" PRIu64
1069
                       ") ack:%s",
1070
                    cnt, seg, seg->seq, seg_abs, TCP_SEG_LEN(seg),
1071
                    seg_abs + (uint64_t)TCP_SEG_LEN(seg), STREAM_BASE_OFFSET(stream), acked);
1072
            last_re = seg_abs + (uint64_t)TCP_SEG_LEN(seg);
1073
            cnt++;
1074
            size += (uint64_t)TCP_SEG_LEN(seg);
1075
        }
1076
1077
        SCLogDebug("size %"PRIu64", cnt %"PRIu32, size, cnt);
1078
        return size;
1079
    }
1080
    return (uint64_t)0;
1081
}
1082
1083
static void GetSessionSize(TcpSession *ssn, Packet *p)
1084
{
1085
    uint64_t size = 0;
1086
    if (ssn) {
1087
        size = GetStreamSize(&ssn->client);
1088
        size += GetStreamSize(&ssn->server);
1089
1090
        //if (size > 900000)
1091
        //    SCLogInfo("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt);
1092
        SCLogDebug("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt);
1093
    }
1094
}
1095
#endif
1096
1097
static inline bool GapAhead(const TcpStream *stream, StreamingBufferBlock *cur_blk)
1098
87.6k
{
1099
87.6k
    StreamingBufferBlock *nblk = SBB_RB_NEXT(cur_blk);
1100
87.6k
    if (nblk && (cur_blk->offset + cur_blk->len < nblk->offset) &&
1101
15.4k
            GetAbsLastAck(stream) > (cur_blk->offset + cur_blk->len)) {
1102
8.47k
        return true;
1103
8.47k
    }
1104
79.1k
    return false;
1105
87.6k
}
1106
1107
/** \internal
1108
 *
1109
 *  Get buffer, or first part of the buffer if data gaps exist.
1110
 *
1111
 *  \brief get stream data from offset
1112
 *  \param offset stream offset
1113
 *  \param check_for_gap check if there is a gap ahead. Optional as it is only
1114
 *                       needed for app-layer incomplete support.
1115
 *  \retval bool pkt loss ahead */
1116
static bool GetAppBuffer(const TcpStream *stream, const uint8_t **data, uint32_t *data_len,
1117
        uint64_t offset, const bool check_for_gap)
1118
15.0M
{
1119
15.0M
    const uint8_t *mydata;
1120
15.0M
    uint32_t mydata_len;
1121
15.0M
    bool gap_ahead = false;
1122
1123
15.0M
    if (RB_EMPTY(&stream->sb.sbb_tree)) {
1124
13.7M
        SCLogDebug("getting one blob");
1125
1126
13.7M
        StreamingBufferGetDataAtOffset(&stream->sb, &mydata, &mydata_len, offset);
1127
1128
13.7M
        *data = mydata;
1129
13.7M
        *data_len = mydata_len;
1130
13.7M
    } else {
1131
1.31M
        SCLogDebug("block mode");
1132
1.31M
        StreamingBufferBlock key = { .offset = offset, .len = 0 };
1133
1.31M
        StreamingBufferBlock *blk = SBB_RB_FIND_INCLUSIVE((struct SBB *)&stream->sb.sbb_tree, &key);
1134
1.31M
        if (blk == NULL) {
1135
330k
            *data = NULL;
1136
330k
            *data_len = 0;
1137
330k
            return false;
1138
330k
        }
1139
979k
        SCLogDebug("blk %p blk->offset %" PRIu64 ", blk->len %u", blk, blk->offset, blk->len);
1140
1141
        /* block at expected offset */
1142
979k
        if (blk->offset == offset) {
1143
225k
            SCLogDebug("blk at offset");
1144
1145
225k
            StreamingBufferSBBGetData(&stream->sb, blk, data, data_len);
1146
225k
            BUG_ON(blk->len != *data_len);
1147
1148
225k
            gap_ahead = check_for_gap && GapAhead(stream, blk);
1149
1150
        /* block past out offset */
1151
754k
        } else if (blk->offset > offset) {
1152
410k
            SCLogDebug("gap, want data at offset %"PRIu64", "
1153
410k
                    "got data at %"PRIu64". GAP of size %"PRIu64,
1154
410k
                    offset, blk->offset, blk->offset - offset);
1155
410k
            *data = NULL;
1156
410k
            *data_len = blk->offset - offset;
1157
1158
        /* block starts before offset, but ends after */
1159
410k
        } else if (offset > blk->offset && offset <= (blk->offset + blk->len)) {
1160
343k
            SCLogDebug("get data from offset %"PRIu64". SBB %"PRIu64"/%u",
1161
343k
                    offset, blk->offset, blk->len);
1162
343k
            StreamingBufferSBBGetDataAtOffset(&stream->sb, blk, data, data_len, offset);
1163
343k
            SCLogDebug("data %p, data_len %u", *data, *data_len);
1164
1165
343k
            gap_ahead = check_for_gap && GapAhead(stream, blk);
1166
1167
343k
        } else {
1168
0
            *data = NULL;
1169
0
            *data_len = 0;
1170
0
        }
1171
979k
    }
1172
14.7M
    return gap_ahead;
1173
15.0M
}
1174
1175
/** \internal
1176
 *  \brief check to see if we should declare a GAP
1177
 *  Call this when the app layer didn't get data at the requested
1178
 *  offset.
1179
 */
1180
static inline bool CheckGap(TcpSession *ssn, TcpStream *stream, Packet *p)
1181
135k
{
1182
135k
    const uint64_t app_progress = STREAM_APP_PROGRESS(stream);
1183
135k
    const int ackadded = (ssn->state >= TCP_FIN_WAIT1) ? 1 : 0;
1184
135k
    const uint64_t last_ack_abs = GetAbsLastAck(stream) - (uint64_t)ackadded;
1185
1186
135k
    SCLogDebug("last_ack %u abs %" PRIu64, stream->last_ack, last_ack_abs);
1187
135k
    SCLogDebug("next_seq %u", stream->next_seq);
1188
1189
    /* if last_ack_abs is beyond the app_progress data that we haven't seen
1190
     * has been ack'd. This looks like a GAP. */
1191
135k
    if (last_ack_abs > app_progress) {
1192
        /* however, we can accept ACKs a bit too liberally. If last_ack
1193
         * is beyond next_seq, we only consider it a gap now if we do
1194
         * already have data beyond the gap. */
1195
130k
        if (SEQ_GT(stream->last_ack, stream->next_seq)) {
1196
14.6k
            if (RB_EMPTY(&stream->sb.sbb_tree)) {
1197
0
                SCLogDebug("packet %" PRIu64 ": no GAP. "
1198
0
                           "next_seq %u < last_ack %u, but no data in list",
1199
0
                        p->pcap_cnt, stream->next_seq, stream->last_ack);
1200
0
                return false;
1201
14.6k
            } else {
1202
14.6k
                const uint64_t next_seq_abs =
1203
14.6k
                        STREAM_BASE_OFFSET(stream) + (stream->next_seq - stream->base_seq);
1204
14.6k
                const StreamingBufferBlock *blk = stream->sb.head;
1205
14.6k
                if (blk->offset > next_seq_abs && blk->offset < last_ack_abs) {
1206
                    /* ack'd data after the gap */
1207
430
                    SCLogDebug("packet %" PRIu64 ": GAP. "
1208
430
                               "next_seq %u < last_ack %u, but ACK'd data beyond gap.",
1209
430
                            p->pcap_cnt, stream->next_seq, stream->last_ack);
1210
430
                    return true;
1211
430
                }
1212
14.6k
            }
1213
14.6k
        }
1214
1215
129k
        SCLogDebug("packet %" PRIu64 ": GAP! "
1216
129k
                   "last_ack_abs %" PRIu64 " > app_progress %" PRIu64 ", "
1217
129k
                   "but we have no data.",
1218
129k
                p->pcap_cnt, last_ack_abs, app_progress);
1219
129k
        return true;
1220
130k
    }
1221
4.98k
    SCLogDebug("packet %"PRIu64": no GAP. "
1222
4.98k
            "last_ack_abs %"PRIu64" <= app_progress %"PRIu64,
1223
4.98k
            p->pcap_cnt, last_ack_abs, app_progress);
1224
4.98k
    return false;
1225
135k
}
1226
1227
static inline uint32_t AdjustToAcked(const Packet *p,
1228
        const TcpSession *ssn, const TcpStream *stream,
1229
        const uint64_t app_progress, const uint32_t data_len)
1230
8.42M
{
1231
8.42M
    uint32_t adjusted = data_len;
1232
1233
    /* get window of data that is acked */
1234
8.42M
    if (StreamTcpInlineMode() == FALSE) {
1235
8.42M
        SCLogDebug("ssn->state %s", StreamTcpStateAsString(ssn->state));
1236
8.42M
        if (data_len == 0 || ((ssn->state < TCP_CLOSED ||
1237
54.7k
                                      (ssn->state == TCP_CLOSED &&
1238
54.7k
                                              (ssn->flags & STREAMTCP_FLAG_CLOSED_BY_RST) != 0)) &&
1239
4.71M
                                     (p->flags & PKT_PSEUDO_STREAM_END))) {
1240
            // fall through, we use all available data
1241
4.71M
        } else {
1242
3.70M
            const uint64_t last_ack_abs = GetAbsLastAck(stream);
1243
3.70M
            DEBUG_VALIDATE_BUG_ON(app_progress > last_ack_abs);
1244
1245
            /* see if the buffer contains unack'd data as well */
1246
3.70M
            if (app_progress <= last_ack_abs && app_progress + data_len > last_ack_abs) {
1247
180k
                uint32_t check = data_len;
1248
180k
                adjusted = last_ack_abs - app_progress;
1249
180k
                BUG_ON(adjusted > check);
1250
180k
                SCLogDebug("data len adjusted to %u to make sure only ACK'd "
1251
180k
                        "data is considered", adjusted);
1252
180k
            }
1253
3.70M
        }
1254
8.42M
    }
1255
8.42M
    return adjusted;
1256
8.42M
}
1257
1258
/** \internal
1259
 *  \brief get stream buffer and update the app-layer
1260
 *  \param stream pointer to pointer as app-layer can switch flow dir
1261
 *  \retval 0 success
1262
 */
1263
static int ReassembleUpdateAppLayer (ThreadVars *tv,
1264
        TcpReassemblyThreadCtx *ra_ctx,
1265
        TcpSession *ssn, TcpStream **stream,
1266
        Packet *p, enum StreamUpdateDir dir)
1267
11.3M
{
1268
11.3M
    uint64_t app_progress = STREAM_APP_PROGRESS(*stream);
1269
1270
11.3M
    SCLogDebug("app progress %"PRIu64, app_progress);
1271
#ifdef DEBUG
1272
    uint64_t last_ack_abs = GetAbsLastAck(*stream);
1273
    SCLogDebug("last_ack %u (abs %" PRIu64 "), base_seq %u", (*stream)->last_ack, last_ack_abs,
1274
            (*stream)->base_seq);
1275
#endif
1276
11.3M
    const uint8_t *mydata;
1277
11.3M
    uint32_t mydata_len;
1278
11.3M
    bool last_was_gap = false;
1279
1280
15.0M
    while (1) {
1281
15.0M
        const uint8_t flags = StreamGetAppLayerFlags(ssn, *stream, p);
1282
15.0M
        bool check_for_gap_ahead = ((*stream)->data_required > 0);
1283
15.0M
        bool gap_ahead =
1284
15.0M
                GetAppBuffer(*stream, &mydata, &mydata_len, app_progress, check_for_gap_ahead);
1285
15.0M
        SCLogDebug("gap_ahead %s mydata_len %u", BOOL2STR(gap_ahead), mydata_len);
1286
15.0M
        if (last_was_gap && mydata_len == 0) {
1287
0
            break;
1288
0
        }
1289
15.0M
        last_was_gap = false;
1290
1291
        /* make sure to only deal with ACK'd data */
1292
15.0M
        mydata_len = AdjustToAcked(p, ssn, *stream, app_progress, mydata_len);
1293
15.0M
        DEBUG_VALIDATE_BUG_ON(mydata_len > (uint32_t)INT_MAX);
1294
15.0M
        if (mydata == NULL && mydata_len > 0 && CheckGap(ssn, *stream, p)) {
1295
329k
            SCLogDebug("sending GAP to app-layer (size: %u)", mydata_len);
1296
1297
329k
            int r = AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, NULL, mydata_len,
1298
329k
                    StreamGetAppLayerFlags(ssn, *stream, p) | STREAM_GAP, dir);
1299
329k
            AppLayerProfilingStore(ra_ctx->app_tctx, p);
1300
1301
329k
            StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP);
1302
329k
            (*stream)->flags |= STREAMTCP_STREAM_FLAG_HAS_GAP;
1303
329k
            StatsIncr(tv, ra_ctx->counter_tcp_reass_gap);
1304
329k
            ssn->flags |= STREAMTCP_FLAG_LOSSY_BE_LIBERAL;
1305
1306
            /* AppLayerHandleTCPData has likely updated progress. */
1307
329k
            const bool no_progress_update = (app_progress == STREAM_APP_PROGRESS(*stream));
1308
329k
            app_progress = STREAM_APP_PROGRESS(*stream);
1309
1310
            /* a GAP also consumes 'data required'. TODO perhaps we can use
1311
             * this to skip post GAP data until the start of a next record. */
1312
329k
            if ((*stream)->data_required > 0) {
1313
11.3k
                if ((*stream)->data_required > mydata_len) {
1314
6.31k
                    (*stream)->data_required -= mydata_len;
1315
6.31k
                } else {
1316
4.99k
                    (*stream)->data_required = 0;
1317
4.99k
                }
1318
11.3k
            }
1319
329k
            if (r < 0)
1320
258k
                return 0;
1321
70.7k
            if (no_progress_update)
1322
825
                break;
1323
69.8k
            last_was_gap = true;
1324
69.8k
            continue;
1325
1326
14.7M
        } else if (flags & STREAM_DEPTH) {
1327
3.93k
            SCLogDebug("DEPTH");
1328
            // we're just called once with this flag, so make sure we pass it on
1329
3.93k
            if (mydata == NULL && mydata_len > 0) {
1330
0
                mydata_len = 0;
1331
0
            }
1332
14.7M
        } else if (mydata == NULL || (mydata_len == 0 && ((flags & STREAM_EOF) == 0))) {
1333
8.71M
            SCLogDebug("GAP?1");
1334
            /* Possibly a gap, but no new data. */
1335
8.71M
            if ((p->flags & PKT_PSEUDO_STREAM_END) == 0 || ssn->state < TCP_CLOSED)
1336
8.69M
                SCReturnInt(0);
1337
1338
21.1k
            mydata = NULL;
1339
21.1k
            mydata_len = 0;
1340
21.1k
            SCLogDebug("%"PRIu64" got %p/%u", p->pcap_cnt, mydata, mydata_len);
1341
21.1k
            break;
1342
8.71M
        }
1343
6.00M
        DEBUG_VALIDATE_BUG_ON(mydata == NULL && mydata_len > 0);
1344
1345
6.00M
        SCLogDebug("stream %p data in buffer %p of len %u and offset %"PRIu64,
1346
6.00M
                *stream, &(*stream)->sb, mydata_len, app_progress);
1347
1348
6.00M
        if ((p->flags & PKT_PSEUDO_STREAM_END) == 0 || ssn->state < TCP_CLOSED) {
1349
5.96M
            SCLogDebug("GAP?2");
1350
5.96M
            if (mydata_len < (*stream)->data_required) {
1351
1.77M
                SCLogDebug("GAP?3 gap_head %s", BOOL2STR(gap_ahead));
1352
1.77M
                if (gap_ahead) {
1353
10.7k
                    SCLogDebug("GAP while expecting more data (expect %u, gap size %u)",
1354
10.7k
                            (*stream)->data_required, mydata_len);
1355
10.7k
                    (*stream)->app_progress_rel += mydata_len;
1356
10.7k
                    (*stream)->data_required -= mydata_len;
1357
                    // TODO send incomplete data to app-layer with special flag
1358
                    // indicating its all there is for this rec?
1359
1.76M
                } else {
1360
1.76M
                    SCReturnInt(0);
1361
1.76M
                }
1362
10.7k
                app_progress = STREAM_APP_PROGRESS(*stream);
1363
10.7k
                continue;
1364
1.77M
            }
1365
5.96M
        }
1366
4.23M
        (*stream)->data_required = 0;
1367
1368
4.23M
        SCLogDebug("parser");
1369
        /* update the app-layer */
1370
4.23M
        (void)AppLayerHandleTCPData(
1371
4.23M
                tv, ra_ctx, p, p->flow, ssn, stream, (uint8_t *)mydata, mydata_len, flags, dir);
1372
4.23M
        AppLayerProfilingStore(ra_ctx->app_tctx, p);
1373
4.23M
        AppLayerFrameDump(p->flow);
1374
4.23M
        uint64_t new_app_progress = STREAM_APP_PROGRESS(*stream);
1375
4.23M
        if (new_app_progress == app_progress || FlowChangeProto(p->flow))
1376
649k
            break;
1377
3.58M
        app_progress = new_app_progress;
1378
3.58M
        if (flags & STREAM_DEPTH)
1379
11
            break;
1380
3.58M
    }
1381
1382
11.3M
    SCReturnInt(0);
1383
11.3M
}
1384
1385
/**
1386
 *  \brief Update the stream reassembly upon receiving a packet.
1387
 *
1388
 *  For IDS mode, the stream is in the opposite direction of the packet,
1389
 *  as the ACK-packet is ACK'ing the stream.
1390
 *
1391
 *  One of the utilities call by this function AppLayerHandleTCPData(),
1392
 *  has a feature where it will call this very same function for the
1393
 *  stream opposing the stream it is called with.  This shouldn't cause
1394
 *  any issues, since processing of each stream is independent of the
1395
 *  other stream.
1396
 */
1397
int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
1398
                                 TcpSession *ssn, TcpStream *stream,
1399
                                 Packet *p, enum StreamUpdateDir dir)
1400
12.7M
{
1401
12.7M
    SCEnter();
1402
1403
    /* this function can be directly called by app layer protocol
1404
     * detection. */
1405
12.7M
    if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) ||
1406
11.6M
        (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
1407
1.06M
        SCLogDebug("stream no reassembly flag set or app-layer disabled.");
1408
1.06M
        SCReturnInt(0);
1409
1.06M
    }
1410
1411
#ifdef DEBUG
1412
    SCLogDebug("stream->seg_tree RB_MIN %p", RB_MIN(TCPSEG, &stream->seg_tree));
1413
    GetSessionSize(ssn, p);
1414
#endif
1415
    /* if no segments are in the list or all are already processed,
1416
     * and state is beyond established, we send an empty msg */
1417
11.6M
    if (!STREAM_HAS_SEEN_DATA(stream) || STREAM_RIGHT_EDGE(stream) <= STREAM_APP_PROGRESS(stream))
1418
5.28M
    {
1419
        /* send an empty EOF msg if we have no segments but TCP state
1420
         * is beyond ESTABLISHED */
1421
5.28M
        if (ssn->state >= TCP_CLOSING || (p->flags & PKT_PSEUDO_STREAM_END)) {
1422
267k
            SCLogDebug("sending empty eof message");
1423
            /* send EOF to app layer */
1424
267k
            AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, &stream, NULL, 0,
1425
267k
                    StreamGetAppLayerFlags(ssn, stream, p), dir);
1426
267k
            AppLayerProfilingStore(ra_ctx->app_tctx, p);
1427
1428
267k
            SCReturnInt(0);
1429
267k
        }
1430
5.28M
    }
1431
1432
    /* with all that out of the way, lets update the app-layer */
1433
11.3M
    return ReassembleUpdateAppLayer(tv, ra_ctx, ssn, &stream, p, dir);
1434
11.6M
}
1435
1436
/** \internal
1437
 *  \brief get stream data from offset
1438
 *  \param offset stream offset */
1439
static int GetRawBuffer(const TcpStream *stream, const uint8_t **data, uint32_t *data_len,
1440
        StreamingBufferBlock **iter, uint64_t offset, uint64_t *data_offset)
1441
1.32M
{
1442
1.32M
    const uint8_t *mydata;
1443
1.32M
    uint32_t mydata_len;
1444
1.32M
    if (RB_EMPTY(&stream->sb.sbb_tree)) {
1445
827k
        SCLogDebug("getting one blob for offset %"PRIu64, offset);
1446
1447
827k
        uint64_t roffset = offset;
1448
827k
        if (offset)
1449
538k
            StreamingBufferGetDataAtOffset(&stream->sb, &mydata, &mydata_len, offset);
1450
288k
        else {
1451
288k
            StreamingBufferGetData(&stream->sb, &mydata, &mydata_len, &roffset);
1452
288k
        }
1453
1454
827k
        *data = mydata;
1455
827k
        *data_len = mydata_len;
1456
827k
        *data_offset = roffset;
1457
827k
    } else {
1458
498k
        SCLogDebug("multiblob %s. Want offset %"PRIu64,
1459
498k
                *iter == NULL ? "starting" : "continuing", offset);
1460
498k
        if (*iter == NULL) {
1461
360k
            StreamingBufferBlock key = { .offset = offset, .len = 0 };
1462
360k
            *iter = SBB_RB_FIND_INCLUSIVE((struct SBB *)&stream->sb.sbb_tree, &key);
1463
360k
            SCLogDebug("*iter %p", *iter);
1464
360k
        }
1465
498k
        if (*iter == NULL) {
1466
1.14k
            SCLogDebug("no data");
1467
1.14k
            *data = NULL;
1468
1.14k
            *data_len = 0;
1469
1.14k
            *data_offset = 0;
1470
1.14k
            return 0;
1471
1.14k
        }
1472
497k
        SCLogDebug("getting multiple blobs. Iter %p, %"PRIu64"/%u", *iter, (*iter)->offset, (*iter)->len);
1473
1474
497k
        StreamingBufferSBBGetData(&stream->sb, (*iter), &mydata, &mydata_len);
1475
497k
        SCLogDebug("mydata %p", mydata);
1476
1477
497k
        if ((*iter)->offset < offset) {
1478
205k
            uint64_t delta = offset - (*iter)->offset;
1479
205k
            if (delta < mydata_len) {
1480
205k
                *data = mydata + delta;
1481
205k
                *data_len = mydata_len - delta;
1482
205k
                *data_offset = offset;
1483
205k
            } else {
1484
0
                SCLogDebug("no data (yet)");
1485
0
                *data = NULL;
1486
0
                *data_len = 0;
1487
0
                *data_offset = 0;
1488
0
            }
1489
1490
291k
        } else {
1491
291k
            *data = mydata;
1492
291k
            *data_len = mydata_len;
1493
291k
            *data_offset = (*iter)->offset;
1494
291k
        }
1495
1496
497k
        *iter = SBB_RB_NEXT(*iter);
1497
497k
        SCLogDebug("*iter %p", *iter);
1498
497k
    }
1499
1.32M
    return 0;
1500
1.32M
}
1501
1502
/** \brief does the stream engine have data to inspect?
1503
 *
1504
 *  Returns true if there is data to inspect. In IDS case this is
1505
 *  about ACK'd data in the packet's direction.
1506
 *
1507
 *  In the IPS case this is about the packet itself.
1508
 */
1509
bool StreamReassembleRawHasDataReady(TcpSession *ssn, Packet *p)
1510
8.06M
{
1511
8.06M
    TcpStream *stream;
1512
8.06M
    if (PKT_IS_TOSERVER(p)) {
1513
4.52M
        stream = &ssn->client;
1514
4.52M
    } else {
1515
3.54M
        stream = &ssn->server;
1516
3.54M
    }
1517
1518
8.06M
    if (RB_EMPTY(&stream->seg_tree)) {
1519
1.41M
        return false;
1520
1.41M
    }
1521
1522
6.65M
    if (stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY|
1523
6.65M
                         STREAMTCP_STREAM_FLAG_DISABLE_RAW))
1524
5.62M
        return false;
1525
1526
1.02M
    if (StreamTcpInlineMode() == FALSE) {
1527
1.02M
        const uint64_t segs_re_abs =
1528
1.02M
                STREAM_BASE_OFFSET(stream) + stream->segs_right_edge - stream->base_seq;
1529
1.02M
        if (STREAM_RAW_PROGRESS(stream) == segs_re_abs) {
1530
58.8k
            return false;
1531
58.8k
        }
1532
967k
        if (StreamTcpReassembleRawCheckLimit(ssn, stream, p) == 1) {
1533
178k
            return true;
1534
178k
        }
1535
967k
    } else {
1536
0
        if (p->payload_len > 0 && (p->flags & PKT_STREAM_ADD)) {
1537
0
            return true;
1538
0
        }
1539
0
    }
1540
789k
    return false;
1541
1.02M
}
1542
1543
/** \brief update stream engine after detection
1544
 *
1545
 *  Tasked with progressing the 'progress' for Raw reassembly.
1546
 *  2 main scenario's:
1547
 *   1. progress is != 0, so we use this
1548
 *   2. progress is 0, meaning the detect engine didn't touch
1549
 *      raw at all. In this case we need to look into progressing
1550
 *      raw anyway.
1551
 *
1552
 *  Additionally, this function is tasked with disabling raw
1553
 *  reassembly if the app-layer requested to disable it.
1554
 */
1555
void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, const uint64_t progress)
1556
178k
{
1557
178k
    TcpStream *stream;
1558
178k
    if (PKT_IS_TOSERVER(p)) {
1559
104k
        stream = &ssn->client;
1560
104k
    } else {
1561
73.7k
        stream = &ssn->server;
1562
73.7k
    }
1563
1564
178k
    if (progress > STREAM_RAW_PROGRESS(stream)) {
1565
69.6k
        uint32_t slide = progress - STREAM_RAW_PROGRESS(stream);
1566
69.6k
        stream->raw_progress_rel += slide;
1567
69.6k
        stream->flags &= ~STREAMTCP_STREAM_FLAG_TRIGGER_RAW;
1568
1569
108k
    } else if (progress == 0) {
1570
83.0k
        uint64_t target;
1571
83.0k
        if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) == 0) {
1572
73.4k
            target = STREAM_APP_PROGRESS(stream);
1573
73.4k
        } else {
1574
9.60k
            target = GetAbsLastAck(stream);
1575
9.60k
        }
1576
83.0k
        if (target > STREAM_RAW_PROGRESS(stream)) {
1577
20.8k
            uint32_t slide = target - STREAM_RAW_PROGRESS(stream);
1578
20.8k
            stream->raw_progress_rel += slide;
1579
20.8k
        }
1580
83.0k
        stream->flags &= ~STREAMTCP_STREAM_FLAG_TRIGGER_RAW;
1581
1582
83.0k
    } else {
1583
25.8k
        SCLogDebug("p->pcap_cnt %"PRIu64": progress %"PRIu64" app %"PRIu64" raw %"PRIu64" tcp win %"PRIu32,
1584
25.8k
                p->pcap_cnt, progress, STREAM_APP_PROGRESS(stream),
1585
25.8k
                STREAM_RAW_PROGRESS(stream), stream->window);
1586
25.8k
    }
1587
1588
    /* if we were told to accept no more raw data, we can mark raw as
1589
     * disabled now. */
1590
178k
    if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) {
1591
799
        stream->flags |= STREAMTCP_STREAM_FLAG_DISABLE_RAW;
1592
799
        SCLogDebug("ssn %p: STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED set, "
1593
799
            "now that detect ran also set STREAMTCP_STREAM_FLAG_DISABLE_RAW", ssn);
1594
799
    }
1595
1596
178k
    SCLogDebug("stream raw progress now %"PRIu64, STREAM_RAW_PROGRESS(stream));
1597
178k
}
1598
1599
/** \internal
1600
  * \brief get a buffer around the current packet and run the callback on it
1601
  *
1602
  * The inline/IPS scanning method takes the current payload and wraps it in
1603
  * data from other segments.
1604
  *
1605
  * How much data is inspected is controlled by the available data, chunk_size
1606
  * and the payload size of the packet.
1607
  *
1608
  * Large packets: if payload size is close to the chunk_size, where close is
1609
  * defined as more than 67% of the chunk_size, a larger chunk_size will be
1610
  * used: payload_len + 33% of the chunk_size.
1611
  * If the payload size if equal to or bigger than the chunk_size, we use
1612
  * payload len + 33% of the chunk size.
1613
  */
1614
static int StreamReassembleRawInline(TcpSession *ssn, const Packet *p,
1615
        StreamReassembleRawFunc Callback, void *cb_data, uint64_t *progress_out)
1616
0
{
1617
0
    SCEnter();
1618
0
    int r = 0;
1619
1620
0
    TcpStream *stream;
1621
0
    if (PKT_IS_TOSERVER(p)) {
1622
0
        stream = &ssn->client;
1623
0
    } else {
1624
0
        stream = &ssn->server;
1625
0
    }
1626
1627
0
    if (p->payload_len == 0 || (p->flags & PKT_STREAM_ADD) == 0 ||
1628
0
            (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY))
1629
0
    {
1630
0
        *progress_out = STREAM_RAW_PROGRESS(stream);
1631
0
        return 0;
1632
0
    }
1633
1634
0
    uint32_t chunk_size = PKT_IS_TOSERVER(p) ?
1635
0
        stream_config.reassembly_toserver_chunk_size :
1636
0
        stream_config.reassembly_toclient_chunk_size;
1637
0
    if (chunk_size <= p->payload_len) {
1638
0
        chunk_size = p->payload_len + (chunk_size / 3);
1639
0
        SCLogDebug("packet payload len %u, so chunk_size adjusted to %u",
1640
0
                p->payload_len, chunk_size);
1641
0
    } else if (((chunk_size / 3 ) * 2) < p->payload_len) {
1642
0
        chunk_size = p->payload_len + ((chunk_size / 3));
1643
0
        SCLogDebug("packet payload len %u, so chunk_size adjusted to %u",
1644
0
                p->payload_len, chunk_size);
1645
0
    }
1646
1647
0
    uint64_t packet_leftedge_abs = STREAM_BASE_OFFSET(stream) + (TCP_GET_SEQ(p) - stream->base_seq);
1648
0
    uint64_t packet_rightedge_abs = packet_leftedge_abs + p->payload_len;
1649
0
    SCLogDebug("packet_leftedge_abs %"PRIu64", rightedge %"PRIu64,
1650
0
            packet_leftedge_abs, packet_rightedge_abs);
1651
1652
0
    const uint8_t *mydata = NULL;
1653
0
    uint32_t mydata_len = 0;
1654
0
    uint64_t mydata_offset = 0;
1655
    /* simply return progress from the block we inspected. */
1656
0
    bool return_progress = false;
1657
1658
0
    if (RB_EMPTY(&stream->sb.sbb_tree)) {
1659
        /* continues block */
1660
0
        StreamingBufferGetData(&stream->sb, &mydata, &mydata_len, &mydata_offset);
1661
0
        return_progress = true;
1662
1663
0
    } else {
1664
0
        SCLogDebug("finding our SBB from offset %"PRIu64, packet_leftedge_abs);
1665
        /* find our block */
1666
0
        StreamingBufferBlock key = { .offset = packet_leftedge_abs, .len = p->payload_len };
1667
0
        StreamingBufferBlock *sbb = SBB_RB_FIND_INCLUSIVE(&stream->sb.sbb_tree, &key);
1668
0
        if (sbb) {
1669
0
            SCLogDebug("found %p offset %"PRIu64" len %u", sbb, sbb->offset, sbb->len);
1670
0
            StreamingBufferSBBGetData(&stream->sb, sbb, &mydata, &mydata_len);
1671
0
            mydata_offset = sbb->offset;
1672
0
        }
1673
0
    }
1674
1675
    /* this can only happen if the segment insert of our current 'p' failed */
1676
0
    uint64_t mydata_rightedge_abs = mydata_offset + mydata_len;
1677
0
    if ((mydata == NULL || mydata_len == 0) || /* no data */
1678
0
            (mydata_offset >= packet_rightedge_abs || /* data all to the right */
1679
0
             packet_leftedge_abs >= mydata_rightedge_abs) || /* data all to the left */
1680
0
            (packet_leftedge_abs < mydata_offset || /* data missing at the start */
1681
0
             packet_rightedge_abs > mydata_rightedge_abs)) /* data missing at the end */
1682
0
    {
1683
        /* no data, or data is incomplete or wrong: use packet data */
1684
0
        mydata = p->payload;
1685
0
        mydata_len = p->payload_len;
1686
0
        mydata_offset = packet_leftedge_abs;
1687
        //mydata_rightedge_abs = packet_rightedge_abs;
1688
0
    } else {
1689
        /* adjust buffer to match chunk_size */
1690
0
        SCLogDebug("chunk_size %u mydata_len %u", chunk_size, mydata_len);
1691
0
        if (mydata_len > chunk_size) {
1692
0
            uint32_t excess = mydata_len - chunk_size;
1693
0
            SCLogDebug("chunk_size %u mydata_len %u excess %u", chunk_size, mydata_len, excess);
1694
1695
0
            if (mydata_rightedge_abs == packet_rightedge_abs) {
1696
0
                mydata += excess;
1697
0
                mydata_len -= excess;
1698
0
                mydata_offset += excess;
1699
0
                SCLogDebug("cutting front of the buffer with %u", excess);
1700
0
            } else if (mydata_offset == packet_leftedge_abs) {
1701
0
                mydata_len -= excess;
1702
0
                SCLogDebug("cutting tail of the buffer with %u", excess);
1703
0
            } else {
1704
0
                uint32_t before = (uint32_t)(packet_leftedge_abs - mydata_offset);
1705
0
                uint32_t after = (uint32_t)(mydata_rightedge_abs - packet_rightedge_abs);
1706
0
                SCLogDebug("before %u after %u", before, after);
1707
1708
0
                if (after >= (chunk_size - p->payload_len) / 2) {
1709
                    // more trailing data than we need
1710
1711
0
                    if (before >= (chunk_size - p->payload_len) / 2) {
1712
                        // also more heading data, divide evenly
1713
0
                        before = after = (chunk_size - p->payload_len) / 2;
1714
0
                    } else {
1715
                        // heading data is less than requested, give the
1716
                        // rest to the trailing data
1717
0
                        after = (chunk_size - p->payload_len) - before;
1718
0
                    }
1719
0
                } else {
1720
                    // less trailing data than requested
1721
1722
0
                    if (before >= (chunk_size - p->payload_len) / 2) {
1723
0
                        before = (chunk_size - p->payload_len) - after;
1724
0
                    } else {
1725
                        // both smaller than their requested size
1726
0
                    }
1727
0
                }
1728
1729
                /* adjust the buffer */
1730
0
                uint32_t skip = (uint32_t)(packet_leftedge_abs - mydata_offset) - before;
1731
0
                uint32_t cut = (uint32_t)(mydata_rightedge_abs - packet_rightedge_abs) - after;
1732
0
                DEBUG_VALIDATE_BUG_ON(skip > mydata_len);
1733
0
                DEBUG_VALIDATE_BUG_ON(cut > mydata_len);
1734
0
                DEBUG_VALIDATE_BUG_ON(skip + cut > mydata_len);
1735
0
                mydata += skip;
1736
0
                mydata_len -= (skip + cut);
1737
0
                mydata_offset += skip;
1738
0
            }
1739
0
        }
1740
0
    }
1741
1742
    /* run the callback */
1743
0
    r = Callback(cb_data, mydata, mydata_len, mydata_offset);
1744
0
    BUG_ON(r < 0);
1745
1746
0
    if (return_progress) {
1747
0
        *progress_out = (mydata_offset + mydata_len);
1748
0
    } else {
1749
        /* several blocks of data, so we need to be a bit more careful:
1750
         * - if last_ack is beyond last progress, move progress forward to last_ack
1751
         * - if our block matches or starts before last ack, return right edge of
1752
         *   our block.
1753
         */
1754
0
        const uint64_t last_ack_abs = GetAbsLastAck(stream);
1755
0
        SCLogDebug("last_ack_abs %"PRIu64, last_ack_abs);
1756
1757
0
        if (STREAM_RAW_PROGRESS(stream) < last_ack_abs) {
1758
0
            if (mydata_offset > last_ack_abs) {
1759
                /* gap between us and last ack, set progress to last ack */
1760
0
                *progress_out = last_ack_abs;
1761
0
            } else {
1762
0
                *progress_out = (mydata_offset + mydata_len);
1763
0
            }
1764
0
        } else {
1765
0
            *progress_out = STREAM_RAW_PROGRESS(stream);
1766
0
        }
1767
0
    }
1768
0
    return r;
1769
0
}
1770
1771
/** \brief access 'raw' reassembly data.
1772
 *
1773
 *  Access data as tracked by 'raw' tracker. Data is made available to
1774
 *  callback that is passed to this function.
1775
 *
1776
 *  In the case of IDS the callback may be run multiple times if data
1777
 *  contains gaps. It will then be run for each block of data that is
1778
 *  continuous.
1779
 *
1780
 *  The callback should give on of 2 return values:
1781
 *  - 0 ok
1782
 *  - 1 done
1783
 *  The value 1 will break the loop if there is a block list that is
1784
 *  inspected.
1785
 *
1786
 *  This function will return the 'progress' value that has been
1787
 *  consumed until now.
1788
 *
1789
 *  \param ssn tcp session
1790
 *  \param stream tcp stream
1791
 *  \param Callback the function pointer to the callback function
1792
 *  \param cb_data callback data
1793
 *  \param[in] progress_in progress to work from
1794
 *  \param[in] re right edge of data to consider
1795
 *  \param[out] progress_out absolute progress value of the data this
1796
 *                           call handled.
1797
 *  \param eof we're wrapping up so inspect all data we have, incl unACKd
1798
 *  \param respect_inspect_depth use Stream::min_inspect_depth if set
1799
 *
1800
 *  `respect_inspect_depth` is used to avoid useless inspection of too
1801
 *  much data.
1802
 */
1803
static int StreamReassembleRawDo(const TcpSession *ssn, const TcpStream *stream,
1804
        StreamReassembleRawFunc Callback, void *cb_data, const uint64_t progress_in,
1805
        const uint64_t re, uint64_t *progress_out, bool eof, bool respect_inspect_depth)
1806
1.18M
{
1807
1.18M
    SCEnter();
1808
1.18M
    int r = 0;
1809
1810
1.18M
    StreamingBufferBlock *iter = NULL;
1811
1.18M
    uint64_t progress = progress_in;
1812
1813
    /* loop through available buffers. On no packet loss we'll have a single
1814
     * iteration. On missing data we'll walk the blocks */
1815
1.32M
    while (1) {
1816
1.32M
        const uint8_t *mydata;
1817
1.32M
        uint32_t mydata_len;
1818
1.32M
        uint64_t mydata_offset = 0;
1819
1820
1.32M
        GetRawBuffer(stream, &mydata, &mydata_len, &iter, progress, &mydata_offset);
1821
1.32M
        if (mydata_len == 0) {
1822
15.2k
            SCLogDebug("no data");
1823
15.2k
            break;
1824
15.2k
        }
1825
        //PrintRawDataFp(stdout, mydata, mydata_len);
1826
1827
1.31M
        SCLogDebug("raw progress %"PRIu64, progress);
1828
1.31M
        SCLogDebug("stream %p data in buffer %p of len %u and offset %"PRIu64,
1829
1.31M
                stream, &stream->sb, mydata_len, progress);
1830
1831
1.31M
        if (eof) {
1832
            // inspect all remaining data, ack'd or not
1833
1.24M
        } else {
1834
1.24M
            if (re < progress) {
1835
97
                SCLogDebug("nothing to do");
1836
97
                goto end;
1837
97
            }
1838
1839
1.24M
            SCLogDebug("re %" PRIu64 ", raw_progress %" PRIu64, re, progress);
1840
1.24M
            SCLogDebug("raw_progress + mydata_len %" PRIu64 ", re %" PRIu64, progress + mydata_len,
1841
1.24M
                    re);
1842
1843
            /* see if the buffer contains unack'd data as well */
1844
1.24M
            if (progress + mydata_len > re) {
1845
875k
                uint32_t check = mydata_len;
1846
875k
                mydata_len = re - progress;
1847
875k
                BUG_ON(check < mydata_len);
1848
875k
                SCLogDebug("data len adjusted to %u to make sure only ACK'd "
1849
875k
                        "data is considered", mydata_len);
1850
875k
            }
1851
1.24M
        }
1852
1.31M
        if (mydata_len == 0)
1853
165k
            break;
1854
1855
1.14M
        SCLogDebug("data %p len %u", mydata, mydata_len);
1856
1857
        /* we have data. */
1858
1.14M
        r = Callback(cb_data, mydata, mydata_len, mydata_offset);
1859
1.14M
        BUG_ON(r < 0);
1860
1861
1.14M
        if (mydata_offset == progress) {
1862
949k
            SCLogDebug("progress %"PRIu64" increasing with data len %u to %"PRIu64,
1863
949k
                    progress, mydata_len, progress_in + mydata_len);
1864
1865
949k
            progress += mydata_len;
1866
949k
            SCLogDebug("raw progress now %"PRIu64, progress);
1867
1868
        /* data is beyond the progress we'd like, and before last ack. Gap. */
1869
949k
        } else if (mydata_offset > progress && mydata_offset < re) {
1870
150k
            SCLogDebug("GAP: data is missing from %"PRIu64" (%u bytes), setting to first data we have: %"PRIu64, progress, (uint32_t)(mydata_offset - progress), mydata_offset);
1871
150k
            SCLogDebug("re %" PRIu64, re);
1872
150k
            progress = mydata_offset;
1873
150k
            SCLogDebug("raw progress now %"PRIu64, progress);
1874
1875
            /* data is beyond the progress we'd like, and also beyond the last ack:
1876
             * there is a gap and we can't expect it to get filled anymore. */
1877
150k
        } else if (mydata_offset > progress && mydata_offset == re) {
1878
15.7k
            SCLogDebug("mydata_offset %" PRIu64 ", progress %" PRIu64 ", re %" PRIu64,
1879
15.7k
                    mydata_offset, progress, re);
1880
15.7k
            progress = re;
1881
29.2k
        } else {
1882
29.2k
            SCLogDebug("not increasing progress, data gap => mydata_offset "
1883
29.2k
                       "%"PRIu64" != progress %"PRIu64, mydata_offset, progress);
1884
29.2k
        }
1885
1886
1.14M
        if (iter == NULL || r == 1)
1887
1.00M
            break;
1888
1.14M
    }
1889
1.18M
end:
1890
1.18M
    *progress_out = progress;
1891
1.18M
    return r;
1892
1.18M
}
1893
1894
int StreamReassembleForFrame(TcpSession *ssn, TcpStream *stream, StreamReassembleRawFunc Callback,
1895
        void *cb_data, const uint64_t offset, const bool eof)
1896
322k
{
1897
    /* take app progress as the right edge of used data. */
1898
322k
    const uint64_t app_progress = STREAM_APP_PROGRESS(stream);
1899
322k
    SCLogDebug("app_progress %" PRIu64, app_progress);
1900
1901
322k
    uint64_t unused = 0;
1902
322k
    return StreamReassembleRawDo(
1903
322k
            ssn, stream, Callback, cb_data, offset, app_progress, &unused, eof, false);
1904
322k
}
1905
1906
int StreamReassembleRaw(TcpSession *ssn, const Packet *p,
1907
                        StreamReassembleRawFunc Callback, void *cb_data,
1908
                        uint64_t *progress_out, bool respect_inspect_depth)
1909
320k
{
1910
    /* handle inline separately as the logic is very different */
1911
320k
    if (StreamTcpInlineMode() == TRUE) {
1912
0
        return StreamReassembleRawInline(ssn, p, Callback, cb_data, progress_out);
1913
0
    }
1914
1915
320k
    TcpStream *stream;
1916
320k
    if (PKT_IS_TOSERVER(p)) {
1917
165k
        stream = &ssn->client;
1918
165k
    } else {
1919
155k
        stream = &ssn->server;
1920
155k
    }
1921
1922
320k
    if ((stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY|STREAMTCP_STREAM_FLAG_DISABLE_RAW)) ||
1923
320k
        StreamTcpReassembleRawCheckLimit(ssn, stream, p) == 0)
1924
70.8k
    {
1925
70.8k
        *progress_out = STREAM_RAW_PROGRESS(stream);
1926
70.8k
        return 0;
1927
70.8k
    }
1928
1929
249k
    uint64_t progress = STREAM_RAW_PROGRESS(stream);
1930
    /* if the app layer triggered a flush, and we're supposed to
1931
     * use a minimal inspect depth, we actually take the app progress
1932
     * as that is the right edge of the data. Then we take the window
1933
     * of 'min_inspect_depth' before that. */
1934
1935
249k
    SCLogDebug("respect_inspect_depth %s STREAMTCP_STREAM_FLAG_TRIGGER_RAW %s "
1936
249k
               "stream->min_inspect_depth %u",
1937
249k
            respect_inspect_depth ? "true" : "false",
1938
249k
            (stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW) ? "true" : "false",
1939
249k
            stream->min_inspect_depth);
1940
1941
249k
    if (respect_inspect_depth && (stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW) &&
1942
2.93k
            stream->min_inspect_depth) {
1943
2.92k
        progress = STREAM_APP_PROGRESS(stream);
1944
2.92k
        if (stream->min_inspect_depth >= progress) {
1945
1.06k
            progress = 0;
1946
1.86k
        } else {
1947
1.86k
            progress -= stream->min_inspect_depth;
1948
1.86k
        }
1949
1950
2.92k
        SCLogDebug("stream app %" PRIu64 ", raw %" PRIu64, STREAM_APP_PROGRESS(stream),
1951
2.92k
                STREAM_RAW_PROGRESS(stream));
1952
1953
2.92k
        progress = MIN(progress, STREAM_RAW_PROGRESS(stream));
1954
2.92k
        SCLogDebug("applied min inspect depth due to STREAMTCP_STREAM_FLAG_TRIGGER_RAW: progress "
1955
2.92k
                   "%" PRIu64,
1956
2.92k
                progress);
1957
2.92k
    }
1958
1959
249k
    SCLogDebug("progress %" PRIu64 ", min inspect depth %u %s", progress, stream->min_inspect_depth,
1960
249k
            stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW ? "STREAMTCP_STREAM_FLAG_TRIGGER_RAW"
1961
249k
                                                              : "(no trigger)");
1962
1963
    /* absolute right edge of ack'd data */
1964
249k
    const uint64_t last_ack_abs = GetAbsLastAck(stream);
1965
249k
    SCLogDebug("last_ack_abs %" PRIu64, last_ack_abs);
1966
1967
249k
    return StreamReassembleRawDo(ssn, stream, Callback, cb_data, progress, last_ack_abs,
1968
249k
            progress_out, (p->flags & PKT_PSEUDO_STREAM_END), respect_inspect_depth);
1969
320k
}
1970
1971
int StreamReassembleLog(const TcpSession *ssn, const TcpStream *stream,
1972
        StreamReassembleRawFunc Callback, void *cb_data, const uint64_t progress_in,
1973
        uint64_t *progress_out, const bool eof)
1974
380k
{
1975
380k
    if (stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY))
1976
5
        return 0;
1977
1978
    /* absolute right edge of ack'd data */
1979
380k
    const uint64_t last_ack_abs = GetAbsLastAck(stream);
1980
380k
    SCLogDebug("last_ack_abs %" PRIu64, last_ack_abs);
1981
1982
380k
    return StreamReassembleRawDo(
1983
380k
            ssn, stream, Callback, cb_data, progress_in, last_ack_abs, progress_out, eof, false);
1984
380k
}
1985
1986
/** \internal
1987
 *  \brief update app layer based on received ACK
1988
 *
1989
 *  \retval r 0 on success, -1 on error
1990
 */
1991
static int StreamTcpReassembleHandleSegmentUpdateACK (ThreadVars *tv,
1992
        TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p)
1993
12.1M
{
1994
12.1M
    SCEnter();
1995
1996
12.1M
    if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p, UPDATE_DIR_OPPOSING) < 0)
1997
0
        SCReturnInt(-1);
1998
1999
12.1M
    SCReturnInt(0);
2000
12.1M
}
2001
2002
static void StreamTcpReassembleExceptionPolicyStatsIncr(
2003
        ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, enum ExceptionPolicy policy)
2004
0
{
2005
0
    uint16_t id = ra_ctx->counter_tcp_reas_eps.eps_id[policy];
2006
0
    if (likely(tv && id > 0)) {
2007
0
        StatsIncr(tv, id);
2008
0
    }
2009
0
}
2010
2011
int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
2012
        TcpSession *ssn, TcpStream *stream, Packet *p)
2013
7.24M
{
2014
7.24M
    SCEnter();
2015
2016
7.24M
    DEBUG_VALIDATE_BUG_ON(p->tcph == NULL);
2017
2018
7.24M
    SCLogDebug("ssn %p, stream %p, p %p, p->payload_len %"PRIu16"",
2019
7.24M
                ssn, stream, p, p->payload_len);
2020
2021
    /* default IDS: update opposing side (triggered by ACK) */
2022
7.24M
    enum StreamUpdateDir dir = UPDATE_DIR_OPPOSING;
2023
    /* inline and stream end and flow timeout packets trigger same dir handling */
2024
7.24M
    if (StreamTcpInlineMode()) {
2025
0
        dir = UPDATE_DIR_PACKET;
2026
7.24M
    } else if (p->flags & PKT_PSEUDO_STREAM_END) {
2027
191k
        dir = UPDATE_DIR_PACKET;
2028
7.05M
    } else if (p->tcph->th_flags & TH_RST) { // accepted rst
2029
48.7k
        dir = UPDATE_DIR_PACKET;
2030
7.00M
    } else if ((p->tcph->th_flags & TH_FIN) && ssn->state > TCP_TIME_WAIT) {
2031
60.7k
        if (p->tcph->th_flags & TH_ACK) {
2032
34.3k
            dir = UPDATE_DIR_BOTH;
2033
34.3k
        } else {
2034
26.4k
            dir = UPDATE_DIR_PACKET;
2035
26.4k
        }
2036
6.94M
    } else if (ssn->state == TCP_CLOSED) {
2037
5.91k
        dir = UPDATE_DIR_BOTH;
2038
5.91k
    }
2039
2040
    /* handle ack received */
2041
7.24M
    if ((dir == UPDATE_DIR_OPPOSING || dir == UPDATE_DIR_BOTH)) {
2042
        /* we need to update the opposing stream in
2043
         * StreamTcpReassembleHandleSegmentUpdateACK */
2044
6.97M
        TcpStream *opposing_stream = NULL;
2045
6.97M
        if (stream == &ssn->client) {
2046
4.00M
            opposing_stream = &ssn->server;
2047
4.00M
        } else {
2048
2.96M
            opposing_stream = &ssn->client;
2049
2.96M
        }
2050
2051
6.97M
        const bool reversed_before_ack_handling = (p->flow->flags & FLOW_DIR_REVERSED) != 0;
2052
2053
6.97M
        if (StreamTcpReassembleHandleSegmentUpdateACK(tv, ra_ctx, ssn, opposing_stream, p) != 0) {
2054
0
            SCLogDebug("StreamTcpReassembleHandleSegmentUpdateACK error");
2055
0
            SCReturnInt(-1);
2056
0
        }
2057
2058
        /* StreamTcpReassembleHandleSegmentUpdateACK
2059
         * may swap content of ssn->server and ssn->client structures.
2060
         * We have to continue with initial content of the stream in such case */
2061
6.97M
        const bool reversed_after_ack_handling = (p->flow->flags & FLOW_DIR_REVERSED) != 0;
2062
6.97M
        if (reversed_before_ack_handling != reversed_after_ack_handling) {
2063
16.3k
            SCLogDebug("TCP streams were swapped");
2064
16.3k
            stream = opposing_stream;
2065
16.3k
        }
2066
6.97M
    }
2067
    /* if this segment contains data, insert it */
2068
7.24M
    if (p->payload_len > 0 && !(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) &&
2069
5.30M
            (p->tcph->th_flags & TH_RST) == 0) {
2070
5.27M
        SCLogDebug("calling StreamTcpReassembleHandleSegmentHandleData");
2071
2072
5.27M
        if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) != 0) {
2073
0
            SCLogDebug("StreamTcpReassembleHandleSegmentHandleData error");
2074
            /* failure can only be because of memcap hit, so see if this should lead to a drop */
2075
0
            ExceptionPolicyApply(
2076
0
                    p, stream_config.reassembly_memcap_policy, PKT_DROP_REASON_STREAM_REASSEMBLY);
2077
0
            StreamTcpReassembleExceptionPolicyStatsIncr(
2078
0
                    tv, ra_ctx, stream_config.reassembly_memcap_policy);
2079
0
            SCReturnInt(-1);
2080
0
        }
2081
2082
5.27M
        SCLogDebug("packet %"PRIu64" set PKT_STREAM_ADD", p->pcap_cnt);
2083
5.27M
        p->flags |= PKT_STREAM_ADD;
2084
5.27M
    } else {
2085
1.97M
        SCLogDebug("ssn %p / stream %p: not calling StreamTcpReassembleHandleSegmentHandleData:"
2086
1.97M
                   " p->payload_len %u, STREAMTCP_STREAM_FLAG_NOREASSEMBLY %s",
2087
1.97M
                ssn, stream, p->payload_len,
2088
1.97M
                (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ? "true" : "false");
2089
1.97M
    }
2090
2091
    /* if the STREAMTCP_STREAM_FLAG_DEPTH_REACHED is set, but not the
2092
     * STREAMTCP_STREAM_FLAG_NOREASSEMBLY flag, it means the DEPTH flag
2093
     * was *just* set. In this case we trigger the AppLayer Truncate
2094
     * logic, to inform the applayer no more data in this direction is
2095
     * to be expected. */
2096
7.24M
    if ((stream->flags &
2097
7.24M
                (STREAMTCP_STREAM_FLAG_DEPTH_REACHED|STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) ==
2098
7.24M
            STREAMTCP_STREAM_FLAG_DEPTH_REACHED)
2099
0
    {
2100
0
        SCLogDebug("STREAMTCP_STREAM_FLAG_DEPTH_REACHED, truncate applayer");
2101
0
        if (dir != UPDATE_DIR_PACKET) {
2102
0
            SCLogDebug("override: direction now UPDATE_DIR_PACKET so we "
2103
0
                    "can trigger Truncate");
2104
0
            dir = UPDATE_DIR_PACKET;
2105
0
        }
2106
0
    }
2107
2108
    /* in stream inline mode even if we have no data we call the reassembly
2109
     * functions to handle EOF */
2110
7.24M
    if (dir == UPDATE_DIR_PACKET || dir == UPDATE_DIR_BOTH) {
2111
306k
        SCLogDebug("inline (%s) or PKT_PSEUDO_STREAM_END (%s)",
2112
306k
                StreamTcpInlineMode()?"true":"false",
2113
306k
                (p->flags & PKT_PSEUDO_STREAM_END) ?"true":"false");
2114
306k
        if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p, dir) < 0) {
2115
0
            SCReturnInt(-1);
2116
0
        }
2117
306k
    }
2118
2119
7.24M
    SCReturnInt(0);
2120
7.24M
}
2121
2122
/**
2123
 *  \brief get a segment from the pool
2124
 *
2125
 *  \retval seg Segment from the pool or NULL
2126
 */
2127
TcpSegment *StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx)
2128
9.25M
{
2129
9.25M
    TcpSegment *seg = StreamTcpThreadCacheGetSegment();
2130
9.25M
    if (seg) {
2131
4.77M
        StatsIncr(tv, ra_ctx->counter_tcp_segment_from_cache);
2132
4.77M
        memset(&seg->sbseg, 0, sizeof(seg->sbseg));
2133
4.77M
        return seg;
2134
4.77M
    }
2135
2136
4.47M
    seg = (TcpSegment *)PoolThreadGetById(
2137
4.47M
            segment_thread_pool, (uint16_t)ra_ctx->segment_thread_pool_id);
2138
4.47M
    SCLogDebug("seg we return is %p", seg);
2139
4.47M
    if (seg == NULL) {
2140
        /* Increment the counter to show that we are not able to serve the
2141
           segment request due to memcap limit */
2142
0
        StatsIncr(tv, ra_ctx->counter_tcp_segment_memcap);
2143
4.47M
    } else {
2144
4.47M
        memset(&seg->sbseg, 0, sizeof(seg->sbseg));
2145
4.47M
        StatsIncr(tv, ra_ctx->counter_tcp_segment_from_pool);
2146
4.47M
    }
2147
2148
4.47M
    return seg;
2149
9.25M
}
2150
2151
/**
2152
 *  \brief Trigger RAW stream reassembly
2153
 *
2154
 *  Used by AppLayerTriggerRawStreamReassembly to trigger RAW stream
2155
 *  reassembly from the applayer, for example upon completion of a
2156
 *  HTTP request.
2157
 *
2158
 *  It sets a flag in the stream so that the next Raw call will return
2159
 *  the data.
2160
 *
2161
 *  \param ssn TcpSession
2162
 */
2163
void StreamTcpReassembleTriggerRawReassembly(TcpSession *ssn, int direction)
2164
12.7M
{
2165
#ifdef DEBUG
2166
    BUG_ON(ssn == NULL);
2167
#endif
2168
2169
12.7M
    if (ssn != NULL) {
2170
12.7M
        if (direction == STREAM_TOSERVER) {
2171
10.5M
            ssn->client.flags |= STREAMTCP_STREAM_FLAG_TRIGGER_RAW;
2172
10.5M
        } else {
2173
2.22M
            ssn->server.flags |= STREAMTCP_STREAM_FLAG_TRIGGER_RAW;
2174
2.22M
        }
2175
2176
12.7M
        SCLogDebug("flagged ssn %p for immediate raw reassembly", ssn);
2177
12.7M
    }
2178
12.7M
}
2179
2180
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
2181
29.6M
{
2182
#ifdef DEBUG
2183
    BUG_ON(ssn == NULL);
2184
#endif
2185
2186
29.6M
    if (ssn != NULL) {
2187
29.6M
        if (direction == STREAM_TOSERVER) {
2188
27.6M
            ssn->client.min_inspect_depth = depth;
2189
27.6M
            SCLogDebug("ssn %p: set client.min_inspect_depth to %u", ssn, depth);
2190
27.6M
        } else {
2191
2.01M
            ssn->server.min_inspect_depth = depth;
2192
2.01M
            SCLogDebug("ssn %p: set server.min_inspect_depth to %u", ssn, depth);
2193
2.01M
        }
2194
29.6M
    }
2195
29.6M
}
2196
2197
#ifdef UNITTESTS
2198
/** unit tests and it's support functions below */
2199
2200
#define SET_ISN(stream, setseq)             \
2201
    (stream)->isn = (setseq);               \
2202
    (stream)->base_seq = (setseq) + 1
2203
2204
/** \brief  The Function to create the packet with given payload, which is used
2205
 *          to test the reassembly of the engine.
2206
 *
2207
 *  \param  payload     The variable used to store the payload contents of the
2208
 *                      current packet.
2209
 *  \param  value       The value which current payload will have for this packet
2210
 *  \param  payload_len The length of the filed payload for current packet.
2211
 *  \param  len         Length of the payload array
2212
 */
2213
2214
void StreamTcpCreateTestPacket(uint8_t *payload, uint8_t value,
2215
                               uint8_t payload_len, uint8_t len)
2216
{
2217
    uint8_t i;
2218
    for (i = 0; i < payload_len; i++)
2219
        payload[i] = value;
2220
    for (; i < len; i++)
2221
        payload = NULL;
2222
}
2223
2224
/** \brief  The Function Checks the reassembled stream contents against predefined
2225
 *          stream contents according to OS policy used.
2226
 *
2227
 *  \param  stream_policy   Predefined value of stream for different OS policies
2228
 *  \param  stream          Reassembled stream returned from the reassembly functions
2229
 */
2230
2231
int StreamTcpCheckStreamContents(uint8_t *stream_policy, uint16_t sp_size, TcpStream *stream)
2232
{
2233
    if (StreamingBufferCompareRawData(&stream->sb, stream_policy,(uint32_t)sp_size) == 0)
2234
    {
2235
        //PrintRawDataFp(stdout, stream_policy, sp_size);
2236
        return 0;
2237
    }
2238
    return 1;
2239
}
2240
2241
static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len)
2242
{
2243
    if (StreamingBufferCompareRawData(&stream->sb,
2244
                data, data_len) == 0)
2245
    {
2246
        SCReturnInt(0);
2247
    }
2248
    SCLogInfo("OK");
2249
    PrintRawDataFp(stdout, data, data_len);
2250
    return 1;
2251
}
2252
2253
#define MISSED_START(isn)                       \
2254
    TcpReassemblyThreadCtx *ra_ctx = NULL;      \
2255
    TcpSession ssn;                             \
2256
    ThreadVars tv;                              \
2257
    memset(&tv, 0, sizeof(tv));                 \
2258
                                                \
2259
    StreamTcpUTInit(&ra_ctx);                   \
2260
                                                \
2261
    StreamTcpUTSetupSession(&ssn);              \
2262
    StreamTcpUTSetupStream(&ssn.server, (isn)); \
2263
    StreamTcpUTSetupStream(&ssn.client, (isn)); \
2264
                                                \
2265
    TcpStream *stream = &ssn.client;
2266
2267
#define MISSED_END                              \
2268
    StreamTcpUTClearSession(&ssn);              \
2269
    StreamTcpUTDeinit(ra_ctx);                  \
2270
    PASS
2271
2272
#define MISSED_STEP(seq, seg, seglen, buf, buflen) \
2273
    StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen));    \
2274
    FAIL_IF(!(VALIDATE(stream, (uint8_t *)(buf), (buflen))));
2275
2276
#define MISSED_ADD_PAYLOAD(seq, seg, seglen)                                                       \
2277
    StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen));
2278
2279
int UTHCheckGapAtPosition(TcpStream *stream, int pos, uint64_t offset, uint32_t len);
2280
2281
int UTHCheckGapAtPosition(TcpStream *stream, int pos, uint64_t offset, uint32_t len)
2282
{
2283
    int cnt = 0;
2284
    uint64_t last_re = 0;
2285
    StreamingBufferBlock *sbb = NULL;
2286
    RB_FOREACH(sbb, SBB, &stream->sb.sbb_tree)
2287
    {
2288
        if (sbb->offset != last_re) {
2289
            // gap before us
2290
            if (cnt == pos && last_re == offset && len == sbb->offset - last_re) {
2291
                return 1;
2292
            }
2293
            cnt++;
2294
        }
2295
        last_re = sbb->offset + sbb->len;
2296
        cnt++;
2297
    }
2298
    return 0;
2299
}
2300
2301
int UTHCheckDataAtPosition(
2302
        TcpStream *stream, int pos, uint64_t offset, const char *data, uint32_t len);
2303
2304
int UTHCheckDataAtPosition(
2305
        TcpStream *stream, int pos, uint64_t offset, const char *data, uint32_t len)
2306
{
2307
    int cnt = 0;
2308
    uint64_t last_re = 0;
2309
    StreamingBufferBlock *sbb = NULL;
2310
    RB_FOREACH(sbb, SBB, &stream->sb.sbb_tree)
2311
    {
2312
        if (sbb->offset != last_re) {
2313
            // gap before us
2314
            cnt++;
2315
        }
2316
2317
        if (cnt == pos && sbb->offset == offset) {
2318
            const uint8_t *buf = NULL;
2319
            uint32_t buf_len = 0;
2320
            StreamingBufferSBBGetData(&stream->sb, sbb, &buf, &buf_len);
2321
2322
            if (len == buf_len) {
2323
                return (memcmp(data, buf, len) == 0);
2324
            }
2325
        }
2326
2327
        last_re = sbb->offset + sbb->len;
2328
        cnt++;
2329
    }
2330
    return 0;
2331
}
2332
2333
/**
2334
 *  \test   Test the handling of packets missed by both IDS and the end host.
2335
 *          The packet is missed in the starting of the stream.
2336
 *
2337
 *  \retval On success it returns 1 and on failure 0.
2338
 */
2339
2340
static int StreamTcpReassembleTest25 (void)
2341
{
2342
    MISSED_START(6);
2343
    MISSED_ADD_PAYLOAD(10, "BB", 2);
2344
    FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2345
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "BB", 2) == 1);
2346
    MISSED_ADD_PAYLOAD(12, "CC", 2);
2347
    FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2348
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "BBCC", 4) == 1);
2349
    MISSED_STEP(7, "AAA", 3, "AAABBCC", 7);
2350
    MISSED_END;
2351
    PASS;
2352
}
2353
2354
/**
2355
 *  \test   Test the handling of packets missed by both IDS and the end host.
2356
 *          The packet is missed in the middle of the stream.
2357
 *
2358
 *  \retval On success it returns 1 and on failure 0.
2359
 */
2360
2361
static int StreamTcpReassembleTest26 (void)
2362
{
2363
    MISSED_START(9);
2364
    MISSED_STEP(10, "AAA", 3, "AAA", 3);
2365
    MISSED_ADD_PAYLOAD(15, "CC", 2);
2366
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 0, 0, "AAA", 3) == 1);
2367
    FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 1, 3, 2) == 1);
2368
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 2, 5, "CC", 2) == 1);
2369
    MISSED_STEP(13, "BB", 2, "AAABBCC", 7);
2370
    MISSED_END;
2371
}
2372
2373
/**
2374
 *  \test   Test the handling of packets missed by both IDS and the end host.
2375
 *          The packet is missed in the end of the stream.
2376
 *
2377
 *  \retval On success it returns 1 and on failure 0.
2378
 */
2379
2380
static int StreamTcpReassembleTest27 (void)
2381
{
2382
    MISSED_START(9);
2383
    MISSED_STEP(10, "AAA", 3, "AAA", 3);
2384
    MISSED_STEP(13, "BB", 2, "AAABB", 5);
2385
    MISSED_STEP(15, "CC", 2, "AAABBCC", 7);
2386
    MISSED_END;
2387
}
2388
2389
/**
2390
 *  \test   Test the handling of packets missed by IDS, but the end host has
2391
 *          received it and send the acknowledgment of it. The packet is missed
2392
 *          in the starting of the stream.
2393
 *
2394
 *  \retval On success it returns 1 and on failure 0.
2395
 */
2396
2397
static int StreamTcpReassembleTest28 (void)
2398
{
2399
    MISSED_START(6);
2400
    MISSED_ADD_PAYLOAD(10, "AAA", 3);
2401
    FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2402
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "AAA", 3) == 1);
2403
    MISSED_ADD_PAYLOAD(13, "BB", 2);
2404
    FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2405
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "AAABB", 5) == 1);
2406
    ssn.state = TCP_TIME_WAIT;
2407
    MISSED_ADD_PAYLOAD(15, "CC", 2);
2408
    FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2409
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "AAABBCC", 7) == 1);
2410
    MISSED_END;
2411
}
2412
2413
/**
2414
 *  \test   Test the handling of packets missed by IDS, but the end host has
2415
 *          received it and send the acknowledgment of it. The packet is missed
2416
 *          in the middle of the stream.
2417
 *
2418
 *  \retval On success it returns 1 and on failure 0.
2419
 */
2420
2421
static int StreamTcpReassembleTest29 (void)
2422
{
2423
    MISSED_START(9);
2424
    MISSED_STEP(10, "AAA", 3, "AAA", 3);
2425
    ssn.state = TCP_TIME_WAIT;
2426
    MISSED_ADD_PAYLOAD(15, "CC", 2);
2427
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 0, 0, "AAA", 3) == 1);
2428
    FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 1, 3, 2) == 1);
2429
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 2, 5, "CC", 2) == 1);
2430
    MISSED_END;
2431
}
2432
2433
static int StreamTcpReassembleTest33(void)
2434
{
2435
    TcpSession ssn;
2436
    Packet *p = PacketGetFromAlloc();
2437
    FAIL_IF(unlikely(p == NULL));
2438
    Flow f;
2439
    TCPHdr tcph;
2440
    TcpReassemblyThreadCtx *ra_ctx = NULL;
2441
    ssn.client.os_policy = OS_POLICY_BSD;
2442
    uint8_t packet[1460] = "";
2443
2444
    StreamTcpUTInit(&ra_ctx);
2445
    StreamTcpUTSetupSession(&ssn);
2446
2447
    memset(&f, 0, sizeof (Flow));
2448
    memset(&tcph, 0, sizeof (TCPHdr));
2449
    ThreadVars tv;
2450
    memset(&tv, 0, sizeof (ThreadVars));
2451
    FLOW_INITIALIZE(&f);
2452
    f.protoctx = &ssn;
2453
    f.proto = IPPROTO_TCP;
2454
    p->src.family = AF_INET;
2455
    p->dst.family = AF_INET;
2456
    p->proto = IPPROTO_TCP;
2457
    p->flow = &f;
2458
    tcph.th_win = 5480;
2459
    tcph.th_flags = TH_PUSH | TH_ACK;
2460
    p->tcph = &tcph;
2461
    p->flowflags = FLOW_PKT_TOSERVER;
2462
    p->payload = packet;
2463
2464
    p->tcph->th_seq = htonl(10);
2465
    p->tcph->th_ack = htonl(31);
2466
    p->payload_len = 10;
2467
2468
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2469
2470
    p->tcph->th_seq = htonl(20);
2471
    p->tcph->th_ack = htonl(31);
2472
    p->payload_len = 10;
2473
2474
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2475
2476
    p->tcph->th_seq = htonl(40);
2477
    p->tcph->th_ack = htonl(31);
2478
    p->payload_len = 10;
2479
2480
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2481
2482
    p->tcph->th_seq = htonl(5);
2483
    p->tcph->th_ack = htonl(31);
2484
    p->payload_len = 30;
2485
2486
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2487
2488
    StreamTcpUTClearSession(&ssn);
2489
    StreamTcpUTDeinit(ra_ctx);
2490
    SCFree(p);
2491
    PASS;
2492
}
2493
2494
static int StreamTcpReassembleTest34(void)
2495
{
2496
    TcpSession ssn;
2497
    Packet *p = PacketGetFromAlloc();
2498
    FAIL_IF(unlikely(p == NULL));
2499
    Flow f;
2500
    TCPHdr tcph;
2501
    TcpReassemblyThreadCtx *ra_ctx = NULL;
2502
    ssn.client.os_policy = OS_POLICY_BSD;
2503
    uint8_t packet[1460] = "";
2504
2505
    StreamTcpUTInit(&ra_ctx);
2506
    StreamTcpUTSetupSession(&ssn);
2507
    memset(&f, 0, sizeof (Flow));
2508
    memset(&tcph, 0, sizeof (TCPHdr));
2509
    ThreadVars tv;
2510
    memset(&tv, 0, sizeof (ThreadVars));
2511
    FLOW_INITIALIZE(&f);
2512
    f.protoctx = &ssn;
2513
    f.proto = IPPROTO_TCP;
2514
    p->src.family = AF_INET;
2515
    p->dst.family = AF_INET;
2516
    p->proto = IPPROTO_TCP;
2517
    p->flow = &f;
2518
    tcph.th_win = 5480;
2519
    tcph.th_flags = TH_PUSH | TH_ACK;
2520
    p->tcph = &tcph;
2521
    p->flowflags = FLOW_PKT_TOSERVER;
2522
    p->payload = packet;
2523
    SET_ISN(&ssn.client, 857961230);
2524
2525
    p->tcph->th_seq = htonl(857961230);
2526
    p->tcph->th_ack = htonl(31);
2527
    p->payload_len = 304;
2528
2529
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2530
2531
    p->tcph->th_seq = htonl(857961534);
2532
    p->tcph->th_ack = htonl(31);
2533
    p->payload_len = 1460;
2534
2535
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2536
2537
    p->tcph->th_seq = htonl(857963582);
2538
    p->tcph->th_ack = htonl(31);
2539
    p->payload_len = 1460;
2540
2541
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2542
2543
    p->tcph->th_seq = htonl(857960946);
2544
    p->tcph->th_ack = htonl(31);
2545
    p->payload_len = 1460;
2546
2547
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2548
2549
    StreamTcpUTClearSession(&ssn);
2550
    StreamTcpUTDeinit(ra_ctx);
2551
    SCFree(p);
2552
    PASS;
2553
}
2554
2555
/**
2556
 *  \test   Test to make sure that we don't return the segments until the app
2557
 *          layer proto has been detected and after that remove the processed
2558
 *          segments.
2559
 *
2560
 *  \retval On success it returns 1 and on failure 0.
2561
 */
2562
2563
static int StreamTcpReassembleTest39 (void)
2564
{
2565
    Packet *p = PacketGetFromAlloc();
2566
    FAIL_IF(unlikely(p == NULL));
2567
    Flow f;
2568
    ThreadVars tv;
2569
    StreamTcpThread stt;
2570
    TCPHdr tcph;
2571
    PacketQueueNoLock pq;
2572
    memset(&pq,0,sizeof(PacketQueueNoLock));
2573
    memset (&f, 0, sizeof(Flow));
2574
    memset(&tv, 0, sizeof (ThreadVars));
2575
    memset(&stt, 0, sizeof (stt));
2576
    memset(&tcph, 0, sizeof (TCPHdr));
2577
2578
    FLOW_INITIALIZE(&f);
2579
    f.flags = FLOW_IPV4;
2580
    f.proto = IPPROTO_TCP;
2581
    p->flow = &f;
2582
    p->tcph = &tcph;
2583
2584
    StreamTcpUTInit(&stt.ra_ctx);
2585
2586
    /* handshake */
2587
    tcph.th_win = htons(5480);
2588
    tcph.th_flags = TH_SYN;
2589
    p->flowflags = FLOW_PKT_TOSERVER;
2590
    p->payload_len = 0;
2591
    p->payload = NULL;
2592
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2593
2594
    TcpSession *ssn = (TcpSession *)f.protoctx;
2595
    FAIL_IF_NULL(ssn);
2596
2597
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2598
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2599
    FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
2600
    FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
2601
    FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
2602
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2603
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2604
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2605
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2606
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2607
    FAIL_IF(!RB_EMPTY(&ssn->client.seg_tree));
2608
    FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2609
    FAIL_IF(ssn->data_first_seen_dir != 0);
2610
2611
    /* handshake */
2612
    p->tcph->th_ack = htonl(1);
2613
    p->tcph->th_flags = TH_SYN | TH_ACK;
2614
    p->flowflags = FLOW_PKT_TOCLIENT;
2615
    p->payload_len = 0;
2616
    p->payload = NULL;
2617
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2618
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2619
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2620
    FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
2621
    FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
2622
    FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
2623
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2624
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2625
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2626
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2627
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2628
    FAIL_IF(!RB_EMPTY(&ssn->client.seg_tree));
2629
    FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2630
    FAIL_IF(ssn->data_first_seen_dir != 0);
2631
2632
    /* handshake */
2633
    p->tcph->th_ack = htonl(1);
2634
    p->tcph->th_seq = htonl(1);
2635
    p->tcph->th_flags = TH_ACK;
2636
    p->flowflags = FLOW_PKT_TOSERVER;
2637
    p->payload_len = 0;
2638
    p->payload = NULL;
2639
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2640
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2641
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2642
    FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
2643
    FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
2644
    FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
2645
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2646
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2647
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2648
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2649
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2650
    FAIL_IF(!RB_EMPTY(&ssn->client.seg_tree));
2651
    FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2652
    FAIL_IF(ssn->data_first_seen_dir != 0);
2653
2654
    /* partial request */
2655
    uint8_t request1[] = { 0x47, 0x45, };
2656
    p->tcph->th_ack = htonl(1);
2657
    p->tcph->th_seq = htonl(1);
2658
    p->tcph->th_flags = TH_PUSH | TH_ACK;
2659
    p->flowflags = FLOW_PKT_TOSERVER;
2660
    p->payload_len = sizeof(request1);
2661
    p->payload = request1;
2662
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2663
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2664
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2665
    FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
2666
    FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
2667
    FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
2668
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2669
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2670
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2671
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2672
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2673
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2674
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2675
    FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2676
    FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER);
2677
2678
    /* response ack against partial request */
2679
    p->tcph->th_ack = htonl(3);
2680
    p->tcph->th_seq = htonl(1);
2681
    p->tcph->th_flags = TH_ACK;
2682
    p->flowflags = FLOW_PKT_TOCLIENT;
2683
    p->payload_len = 0;
2684
    p->payload = NULL;
2685
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2686
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2687
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2688
    FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
2689
    FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
2690
    FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
2691
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2692
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2693
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2694
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2695
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2696
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2697
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2698
    FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2699
    FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER);
2700
2701
    /* complete partial request */
2702
    uint8_t request2[] = {
2703
        0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64,
2704
        0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20,
2705
        0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30,
2706
        0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20,
2707
        0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73,
2708
        0x74, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d,
2709
        0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x41,
2710
        0x70, 0x61, 0x63, 0x68, 0x65, 0x42, 0x65, 0x6e,
2711
        0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a,
2712
        0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20,
2713
        0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a };
2714
    p->tcph->th_ack = htonl(1);
2715
    p->tcph->th_seq = htonl(3);
2716
    p->tcph->th_flags = TH_PUSH | TH_ACK;
2717
    p->flowflags = FLOW_PKT_TOSERVER;
2718
    p->payload_len = sizeof(request2);
2719
    p->payload = request2;
2720
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2721
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2722
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2723
    FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
2724
    FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
2725
    FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
2726
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2727
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2728
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2729
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2730
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2731
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2732
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2733
    FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2734
    FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2735
    FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER);
2736
2737
    /* response - request ack */
2738
    uint8_t response[] = {
2739
        0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31,
2740
        0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d,
2741
        0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x46,
2742
        0x72, 0x69, 0x2c, 0x20, 0x32, 0x33, 0x20, 0x53,
2743
        0x65, 0x70, 0x20, 0x32, 0x30, 0x31, 0x31, 0x20,
2744
        0x30, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x39,
2745
        0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65,
2746
        0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x41, 0x70,
2747
        0x61, 0x63, 0x68, 0x65, 0x2f, 0x32, 0x2e, 0x32,
2748
        0x2e, 0x31, 0x35, 0x20, 0x28, 0x55, 0x6e, 0x69,
2749
        0x78, 0x29, 0x20, 0x44, 0x41, 0x56, 0x2f, 0x32,
2750
        0x0d, 0x0a, 0x4c, 0x61, 0x73, 0x74, 0x2d, 0x4d,
2751
        0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x3a,
2752
        0x20, 0x54, 0x68, 0x75, 0x2c, 0x20, 0x30, 0x34,
2753
        0x20, 0x4e, 0x6f, 0x76, 0x20, 0x32, 0x30, 0x31,
2754
        0x30, 0x20, 0x31, 0x35, 0x3a, 0x30, 0x34, 0x3a,
2755
        0x34, 0x36, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a,
2756
        0x45, 0x54, 0x61, 0x67, 0x3a, 0x20, 0x22, 0x61,
2757
        0x62, 0x38, 0x39, 0x36, 0x35, 0x2d, 0x32, 0x63,
2758
        0x2d, 0x34, 0x39, 0x34, 0x33, 0x62, 0x37, 0x61,
2759
        0x37, 0x66, 0x37, 0x66, 0x38, 0x30, 0x22, 0x0d,
2760
        0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d,
2761
        0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x3a, 0x20,
2762
        0x62, 0x79, 0x74, 0x65, 0x73, 0x0d, 0x0a, 0x43,
2763
        0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c,
2764
        0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x34,
2765
        0x34, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
2766
        0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63,
2767
        0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, 0x43, 0x6f,
2768
        0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79,
2769
        0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74,
2770
        0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x58,
2771
        0x2d, 0x50, 0x61, 0x64, 0x3a, 0x20, 0x61, 0x76,
2772
        0x6f, 0x69, 0x64, 0x20, 0x62, 0x72, 0x6f, 0x77,
2773
        0x73, 0x65, 0x72, 0x20, 0x62, 0x75, 0x67, 0x0d,
2774
        0x0a, 0x0d, 0x0a, 0x3c, 0x68, 0x74, 0x6d, 0x6c,
2775
        0x3e, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c,
2776
        0x68, 0x31, 0x3e, 0x49, 0x74, 0x20, 0x77, 0x6f,
2777
        0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31,
2778
        0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e,
2779
        0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e };
2780
    p->tcph->th_ack = htonl(88);
2781
    p->tcph->th_seq = htonl(1);
2782
    p->tcph->th_flags = TH_PUSH | TH_ACK;
2783
    p->flowflags = FLOW_PKT_TOCLIENT;
2784
    p->payload_len = sizeof(response);
2785
    p->payload = response;
2786
2787
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2788
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2789
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2790
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2791
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2792
    FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
2793
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2794
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2795
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2796
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2797
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2798
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2799
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2800
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2801
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2802
    FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2803
2804
    /* response ack from request */
2805
    p->tcph->th_ack = htonl(328);
2806
    p->tcph->th_seq = htonl(88);
2807
    p->tcph->th_flags = TH_ACK;
2808
    p->flowflags = FLOW_PKT_TOSERVER;
2809
    p->payload_len = 0;
2810
    p->payload = NULL;
2811
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2812
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2813
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2814
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2815
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2816
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2817
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2818
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2819
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2820
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2821
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2822
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2823
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2824
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2825
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2826
    FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2827
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2828
2829
    /* response - acking */
2830
    p->tcph->th_ack = htonl(88);
2831
    p->tcph->th_seq = htonl(328);
2832
    p->tcph->th_flags = TH_PUSH | TH_ACK;
2833
    p->flowflags = FLOW_PKT_TOCLIENT;
2834
    p->payload_len = 0;
2835
    p->payload = NULL;
2836
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2837
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2838
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2839
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2840
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2841
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2842
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2843
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2844
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2845
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2846
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2847
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2848
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2849
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2850
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2851
    FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2852
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2853
2854
    /* response ack from request */
2855
    p->tcph->th_ack = htonl(328);
2856
    p->tcph->th_seq = htonl(88);
2857
    p->tcph->th_flags = TH_ACK;
2858
    p->flowflags = FLOW_PKT_TOSERVER;
2859
    p->payload_len = 0;
2860
    p->payload = NULL;
2861
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2862
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2863
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2864
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2865
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2866
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2867
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2868
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2869
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2870
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2871
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2872
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2873
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2874
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2875
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2876
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2877
2878
    /* response - acking the request again*/
2879
    p->tcph->th_ack = htonl(88);
2880
    p->tcph->th_seq = htonl(328);
2881
    p->tcph->th_flags = TH_PUSH | TH_ACK;
2882
    p->flowflags = FLOW_PKT_TOCLIENT;
2883
    p->payload_len = 0;
2884
    p->payload = NULL;
2885
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2886
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2887
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2888
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2889
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2890
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2891
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2892
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2893
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2894
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2895
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2896
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2897
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2898
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2899
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2900
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2901
2902
    /*** New Request ***/
2903
2904
    /* partial request */
2905
    p->tcph->th_ack = htonl(328);
2906
    p->tcph->th_seq = htonl(88);
2907
    p->tcph->th_flags = TH_PUSH | TH_ACK;
2908
    p->flowflags = FLOW_PKT_TOSERVER;
2909
    p->payload_len = sizeof(request1);
2910
    p->payload = request1;
2911
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2912
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2913
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2914
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2915
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2916
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2917
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2918
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2919
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2920
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2921
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2922
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2923
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2924
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2925
    FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2926
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2927
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2928
2929
    /* response ack against partial request */
2930
    p->tcph->th_ack = htonl(90);
2931
    p->tcph->th_seq = htonl(328);
2932
    p->tcph->th_flags = TH_ACK;
2933
    p->flowflags = FLOW_PKT_TOCLIENT;
2934
    p->payload_len = 0;
2935
    p->payload = NULL;
2936
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2937
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2938
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2939
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2940
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2941
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2942
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2943
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2944
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2945
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2946
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2947
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2948
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2949
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2950
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2951
    FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2952
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2953
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2954
2955
    /* complete request */
2956
    p->tcph->th_ack = htonl(328);
2957
    p->tcph->th_seq = htonl(90);
2958
    p->tcph->th_flags = TH_PUSH | TH_ACK;
2959
    p->flowflags = FLOW_PKT_TOSERVER;
2960
    p->payload_len = sizeof(request2);
2961
    p->payload = request2;
2962
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2963
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2964
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2965
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2966
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2967
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2968
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2969
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2970
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2971
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2972
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2973
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2974
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2975
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2976
    FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2977
    FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)))));
2978
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2979
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2980
2981
    /* response ack against second partial request */
2982
    p->tcph->th_ack = htonl(175);
2983
    p->tcph->th_seq = htonl(328);
2984
    p->tcph->th_flags = TH_ACK;
2985
    p->flowflags = FLOW_PKT_TOCLIENT;
2986
    p->payload_len = 0;
2987
    p->payload = NULL;
2988
2989
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2990
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2991
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2992
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2993
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2994
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2995
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2996
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2997
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2998
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2999
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
3000
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
3001
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
3002
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
3003
    FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
3004
    FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)))));
3005
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
3006
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
3007
3008
    /* response acking a request */
3009
    p->tcph->th_ack = htonl(175);
3010
    p->tcph->th_seq = htonl(328);
3011
    p->tcph->th_flags = TH_ACK;
3012
    p->flowflags = FLOW_PKT_TOCLIENT;
3013
    p->payload_len = 0;
3014
    p->payload = NULL;
3015
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
3016
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
3017
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
3018
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
3019
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
3020
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
3021
3022
    StreamTcpPruneSession(&f, STREAM_TOSERVER);
3023
    StreamTcpPruneSession(&f, STREAM_TOCLIENT);
3024
3025
    /* request acking a response */
3026
    p->tcph->th_ack = htonl(328);
3027
    p->tcph->th_seq = htonl(175);
3028
    p->tcph->th_flags = TH_ACK;
3029
    p->flowflags = FLOW_PKT_TOSERVER;
3030
    p->payload_len = 0;
3031
    p->payload = NULL;
3032
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
3033
3034
    StreamTcpSessionClear(ssn);
3035
    StreamTcpUTDeinit(stt.ra_ctx);
3036
    SCFree(p);
3037
    PASS;
3038
}
3039
3040
/**
3041
 *  \test   Test to make sure that we sent all the segments from the initial
3042
 *          segments to app layer until we have detected the app layer proto.
3043
 *
3044
 *  \retval On success it returns 1 and on failure 0.
3045
 */
3046
3047
static int StreamTcpReassembleTest40 (void)
3048
{
3049
    Packet *p = PacketGetFromAlloc();
3050
    FAIL_IF_NULL(p);
3051
    Flow *f = NULL;
3052
    TCPHdr tcph;
3053
    TcpSession ssn;
3054
    memset(&tcph, 0, sizeof (TCPHdr));
3055
    ThreadVars tv;
3056
    memset(&tv, 0, sizeof (ThreadVars));
3057
3058
    StreamTcpInitConfig(true);
3059
    StreamTcpUTSetupSession(&ssn);
3060
3061
    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(&tv);
3062
    FAIL_IF_NULL(ra_ctx);
3063
3064
    uint8_t httpbuf1[] = "P";
3065
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3066
    uint8_t httpbuf3[] = "O";
3067
    uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
3068
    uint8_t httpbuf4[] = "S";
3069
    uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
3070
    uint8_t httpbuf5[] = "T \r\n";
3071
    uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
3072
3073
    uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
3074
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3075
3076
    SET_ISN(&ssn.server, 9);
3077
    ssn.server.last_ack = 10;
3078
    SET_ISN(&ssn.client, 9);
3079
    ssn.client.isn = 9;
3080
3081
    f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
3082
    FAIL_IF_NULL(f);
3083
    f->protoctx = &ssn;
3084
    f->proto = IPPROTO_TCP;
3085
    p->flow = f;
3086
3087
    tcph.th_win = htons(5480);
3088
    tcph.th_seq = htonl(10);
3089
    tcph.th_ack = htonl(10);
3090
    tcph.th_flags = TH_ACK|TH_PUSH;
3091
    p->tcph = &tcph;
3092
    p->flowflags = FLOW_PKT_TOSERVER;
3093
    p->payload = httpbuf1;
3094
    p->payload_len = httplen1;
3095
    ssn.state = TCP_ESTABLISHED;
3096
    TcpStream *s = &ssn.client;
3097
    SCLogDebug("1 -- start");
3098
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3099
3100
    p->flowflags = FLOW_PKT_TOCLIENT;
3101
    p->payload = httpbuf2;
3102
    p->payload_len = httplen2;
3103
    tcph.th_seq = htonl(10);
3104
    tcph.th_ack = htonl(11);
3105
    s = &ssn.server;
3106
    ssn.server.last_ack = 11;
3107
    SCLogDebug("2 -- start");
3108
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3109
3110
    p->flowflags = FLOW_PKT_TOSERVER;
3111
    p->payload = httpbuf3;
3112
    p->payload_len = httplen3;
3113
    tcph.th_seq = htonl(11);
3114
    tcph.th_ack = htonl(55);
3115
    s = &ssn.client;
3116
    ssn.client.last_ack = 55;
3117
    SCLogDebug("3 -- start");
3118
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3119
3120
    p->flowflags = FLOW_PKT_TOCLIENT;
3121
    p->payload = httpbuf2;
3122
    p->payload_len = httplen2;
3123
    tcph.th_seq = htonl(55);
3124
    tcph.th_ack = htonl(12);
3125
    s = &ssn.server;
3126
    ssn.server.last_ack = 12;
3127
    SCLogDebug("4 -- start");
3128
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3129
3130
    /* check is have the segment in the list and flagged or not */
3131
    TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3132
    FAIL_IF_NULL(seg);
3133
    FAIL_IF(SEGMENT_BEFORE_OFFSET(&ssn.client, seg, STREAM_APP_PROGRESS(&ssn.client)));
3134
3135
    p->flowflags = FLOW_PKT_TOSERVER;
3136
    p->payload = httpbuf4;
3137
    p->payload_len = httplen4;
3138
    tcph.th_seq = htonl(12);
3139
    tcph.th_ack = htonl(100);
3140
    s = &ssn.client;
3141
    ssn.client.last_ack = 100;
3142
    SCLogDebug("5 -- start");
3143
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3144
3145
    p->flowflags = FLOW_PKT_TOCLIENT;
3146
    p->payload = httpbuf2;
3147
    p->payload_len = httplen2;
3148
    tcph.th_seq = htonl(100);
3149
    tcph.th_ack = htonl(13);
3150
    s = &ssn.server;
3151
    ssn.server.last_ack = 13;
3152
    SCLogDebug("6 -- start");
3153
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3154
3155
    p->flowflags = FLOW_PKT_TOSERVER;
3156
    p->payload = httpbuf5;
3157
    p->payload_len = httplen5;
3158
    tcph.th_seq = htonl(13);
3159
    tcph.th_ack = htonl(145);
3160
    s = &ssn.client;
3161
    ssn.client.last_ack = 145;
3162
    SCLogDebug("7 -- start");
3163
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3164
3165
    p->flowflags = FLOW_PKT_TOCLIENT;
3166
    p->payload = httpbuf2;
3167
    p->payload_len = httplen2;
3168
    tcph.th_seq = htonl(145);
3169
    tcph.th_ack = htonl(16);
3170
    s = &ssn.server;
3171
    ssn.server.last_ack = 16;
3172
    SCLogDebug("8 -- start");
3173
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3174
    FAIL_IF(f->alproto != ALPROTO_HTTP1);
3175
3176
    StreamTcpUTClearSession(&ssn);
3177
    StreamTcpReassembleFreeThreadCtx(ra_ctx);
3178
    StreamTcpFreeConfig(true);
3179
    SCFree(p);
3180
    UTHFreeFlow(f);
3181
    PASS;
3182
}
3183
3184
/** \test   Test the memcap incrementing/decrementing and memcap check */
3185
static int StreamTcpReassembleTest44(void)
3186
{
3187
    StreamTcpInitConfig(true);
3188
    uint32_t memuse = SC_ATOMIC_GET(ra_memuse);
3189
    StreamTcpReassembleIncrMemuse(500);
3190
    FAIL_IF(SC_ATOMIC_GET(ra_memuse) != (memuse+500));
3191
    StreamTcpReassembleDecrMemuse(500);
3192
    FAIL_IF(SC_ATOMIC_GET(ra_memuse) != memuse);
3193
    FAIL_IF(StreamTcpReassembleCheckMemcap(500) != 1);
3194
    FAIL_IF(StreamTcpReassembleCheckMemcap((1 + memuse + SC_ATOMIC_GET(stream_config.reassembly_memcap))) != 0);
3195
    StreamTcpFreeConfig(true);
3196
    FAIL_IF(SC_ATOMIC_GET(ra_memuse) != 0);
3197
    PASS;
3198
}
3199
3200
/**
3201
 *  \test   Test to make sure that reassembly_depth is enforced.
3202
 *
3203
 *  \retval On success it returns 1 and on failure 0.
3204
 */
3205
3206
static int StreamTcpReassembleTest45 (void)
3207
{
3208
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3209
    TcpSession ssn;
3210
    ThreadVars tv;
3211
    memset(&tv, 0, sizeof(tv));
3212
    uint8_t payload[100] = {0};
3213
    uint16_t payload_size = 100;
3214
3215
    StreamTcpUTInit(&ra_ctx);
3216
    stream_config.reassembly_depth = 100;
3217
3218
    StreamTcpUTSetupSession(&ssn);
3219
    ssn.reassembly_depth = 100;
3220
    StreamTcpUTSetupStream(&ssn.server, 100);
3221
    StreamTcpUTSetupStream(&ssn.client, 100);
3222
3223
    int r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size);
3224
    FAIL_IF(r != 0);
3225
    FAIL_IF(ssn.client.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED);
3226
3227
    r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size);
3228
    FAIL_IF(r != 0);
3229
    FAIL_IF(!(ssn.client.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED));
3230
3231
    StreamTcpUTClearStream(&ssn.server);
3232
    StreamTcpUTClearStream(&ssn.client);
3233
    StreamTcpUTClearSession(&ssn);
3234
    StreamTcpUTDeinit(ra_ctx);
3235
    PASS;
3236
}
3237
3238
/**
3239
 *  \test   Test the unlimited config value of reassembly depth.
3240
 *
3241
 *  \retval On success it returns 1 and on failure 0.
3242
 */
3243
3244
static int StreamTcpReassembleTest46 (void)
3245
{
3246
    int result = 0;
3247
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3248
    TcpSession ssn;
3249
    ThreadVars tv;
3250
    memset(&tv, 0, sizeof(tv));
3251
    uint8_t payload[100] = {0};
3252
    uint16_t payload_size = 100;
3253
3254
    StreamTcpUTInit(&ra_ctx);
3255
    stream_config.reassembly_depth = 0;
3256
3257
    StreamTcpUTSetupSession(&ssn);
3258
    StreamTcpUTSetupStream(&ssn.server, 100);
3259
    StreamTcpUTSetupStream(&ssn.client, 100);
3260
3261
    int r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size);
3262
    if (r != 0)
3263
        goto end;
3264
    if (ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
3265
        printf("STREAMTCP_STREAM_FLAG_NOREASSEMBLY set: ");
3266
        goto end;
3267
    }
3268
3269
    r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size);
3270
    if (r != 0)
3271
        goto end;
3272
    if (ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
3273
        printf("STREAMTCP_STREAM_FLAG_NOREASSEMBLY set: ");
3274
        goto end;
3275
    }
3276
3277
    result = 1;
3278
end:
3279
    StreamTcpUTClearStream(&ssn.server);
3280
    StreamTcpUTClearStream(&ssn.client);
3281
    StreamTcpUTClearSession(&ssn);
3282
    StreamTcpUTDeinit(ra_ctx);
3283
    return result;
3284
}
3285
3286
/**
3287
 *  \test   Test to make sure we detect the sequence wrap around and continue
3288
 *          stream reassembly properly.
3289
 *
3290
 *  \retval On success it returns 1 and on failure 0.
3291
 */
3292
3293
static int StreamTcpReassembleTest47 (void)
3294
{
3295
    Packet *p = PacketGetFromAlloc();
3296
    FAIL_IF(unlikely(p == NULL));
3297
    Flow *f = NULL;
3298
    TCPHdr tcph;
3299
    TcpSession ssn;
3300
    ThreadVars tv;
3301
    memset(&tcph, 0, sizeof (TCPHdr));
3302
    memset(&tv, 0, sizeof (ThreadVars));
3303
    StreamTcpInitConfig(true);
3304
    StreamTcpUTSetupSession(&ssn);
3305
    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(&tv);
3306
3307
    uint8_t httpbuf1[] = "GET /EVILSUFF HTTP/1.1\r\n\r\n";
3308
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3309
3310
    SET_ISN(&ssn.server, 572799781UL);
3311
    ssn.server.last_ack = 572799782UL;
3312
3313
    SET_ISN(&ssn.client, 4294967289UL);
3314
    ssn.client.last_ack = 21;
3315
3316
    f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
3317
    FAIL_IF(f == NULL);
3318
    f->protoctx = &ssn;
3319
    f->proto = IPPROTO_TCP;
3320
    p->flow = f;
3321
3322
    tcph.th_win = htons(5480);
3323
    ssn.state = TCP_ESTABLISHED;
3324
    TcpStream *s = NULL;
3325
    uint8_t cnt = 0;
3326
3327
    for (cnt=0; cnt < httplen1; cnt++) {
3328
        tcph.th_seq = htonl(ssn.client.isn + 1 + cnt);
3329
        tcph.th_ack = htonl(572799782UL);
3330
        tcph.th_flags = TH_ACK|TH_PUSH;
3331
        p->tcph = &tcph;
3332
        p->flowflags = FLOW_PKT_TOSERVER;
3333
        p->payload = &httpbuf1[cnt];
3334
        p->payload_len = 1;
3335
        s = &ssn.client;
3336
3337
        FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3338
3339
        p->flowflags = FLOW_PKT_TOCLIENT;
3340
        p->payload = NULL;
3341
        p->payload_len = 0;
3342
        tcph.th_seq = htonl(572799782UL);
3343
        tcph.th_ack = htonl(ssn.client.isn + 1 + cnt);
3344
        tcph.th_flags = TH_ACK;
3345
        p->tcph = &tcph;
3346
        s = &ssn.server;
3347
3348
        FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3349
    }
3350
3351
    FAIL_IF(f->alproto != ALPROTO_HTTP1);
3352
3353
    StreamTcpUTClearSession(&ssn);
3354
    StreamTcpReassembleFreeThreadCtx(ra_ctx);
3355
    StreamTcpFreeConfig(true);
3356
    SCFree(p);
3357
    UTHFreeFlow(f);
3358
    PASS;
3359
}
3360
3361
/** \test 3 in order segments in inline reassembly */
3362
static int StreamTcpReassembleInlineTest01(void)
3363
{
3364
    int ret = 0;
3365
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3366
    ThreadVars tv;
3367
    TcpSession ssn;
3368
    Flow f;
3369
3370
    memset(&tv, 0x00, sizeof(tv));
3371
3372
    StreamTcpUTInit(&ra_ctx);
3373
    StreamTcpUTInitInline();
3374
    StreamTcpUTSetupSession(&ssn);
3375
    StreamTcpUTSetupStream(&ssn.client, 1);
3376
    FLOW_INITIALIZE(&f);
3377
3378
    uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3379
    Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3380
    if (p == NULL) {
3381
        printf("couldn't get a packet: ");
3382
        goto end;
3383
    }
3384
    p->tcph->th_seq = htonl(12);
3385
    p->flow = &f;
3386
3387
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1) {
3388
        printf("failed to add segment 1: ");
3389
        goto end;
3390
    }
3391
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1) {
3392
        printf("failed to add segment 2: ");
3393
        goto end;
3394
    }
3395
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3396
        printf("failed to add segment 3: ");
3397
        goto end;
3398
    }
3399
    ssn.client.next_seq = 17;
3400
    ret = 1;
3401
end:
3402
    FLOW_DESTROY(&f);
3403
    UTHFreePacket(p);
3404
    StreamTcpUTClearSession(&ssn);
3405
    StreamTcpUTDeinit(ra_ctx);
3406
    return ret;
3407
}
3408
3409
/** \test 3 in order segments, then reassemble, add one more and reassemble again.
3410
 *        test the sliding window reassembly.
3411
 */
3412
static int StreamTcpReassembleInlineTest02(void)
3413
{
3414
    int ret = 0;
3415
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3416
    ThreadVars tv;
3417
    TcpSession ssn;
3418
    Flow f;
3419
3420
    memset(&tv, 0x00, sizeof(tv));
3421
3422
    StreamTcpUTInit(&ra_ctx);
3423
    StreamTcpUTInitInline();
3424
    StreamTcpUTSetupSession(&ssn);
3425
    StreamTcpUTSetupStream(&ssn.client, 1);
3426
    FLOW_INITIALIZE(&f);
3427
3428
    uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3429
    Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3430
    if (p == NULL) {
3431
        printf("couldn't get a packet: ");
3432
        goto end;
3433
    }
3434
    p->tcph->th_seq = htonl(12);
3435
    p->flow = &f;
3436
3437
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1) {
3438
        printf("failed to add segment 1: ");
3439
        goto end;
3440
    }
3441
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1) {
3442
        printf("failed to add segment 2: ");
3443
        goto end;
3444
    }
3445
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3446
        printf("failed to add segment 3: ");
3447
        goto end;
3448
    }
3449
    ssn.client.next_seq = 17;
3450
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3451
        printf("failed to add segment 4: ");
3452
        goto end;
3453
    }
3454
    ssn.client.next_seq = 22;
3455
    ret = 1;
3456
end:
3457
    FLOW_DESTROY(&f);
3458
    UTHFreePacket(p);
3459
    StreamTcpUTClearSession(&ssn);
3460
    StreamTcpUTDeinit(ra_ctx);
3461
    return ret;
3462
}
3463
3464
/** \test 3 in order segments, then reassemble, add one more and reassemble again.
3465
 *        test the sliding window reassembly with a small window size so that we
3466
 *        cutting off at the start (left edge)
3467
 */
3468
static int StreamTcpReassembleInlineTest03(void)
3469
{
3470
    int ret = 0;
3471
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3472
    ThreadVars tv;
3473
    TcpSession ssn;
3474
    Flow f;
3475
3476
    memset(&tv, 0x00, sizeof(tv));
3477
3478
    StreamTcpUTInit(&ra_ctx);
3479
    StreamTcpUTInitInline();
3480
    StreamTcpUTSetupSession(&ssn);
3481
    StreamTcpUTSetupStream(&ssn.client, 1);
3482
    FLOW_INITIALIZE(&f);
3483
3484
    stream_config.reassembly_toserver_chunk_size = 15;
3485
3486
    uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3487
    Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3488
    if (p == NULL) {
3489
        printf("couldn't get a packet: ");
3490
        goto end;
3491
    }
3492
    p->tcph->th_seq = htonl(12);
3493
    p->flow = &f;
3494
    p->flowflags |= FLOW_PKT_TOSERVER;
3495
3496
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1) {
3497
        printf("failed to add segment 1: ");
3498
        goto end;
3499
    }
3500
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1) {
3501
        printf("failed to add segment 2: ");
3502
        goto end;
3503
    }
3504
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3505
        printf("failed to add segment 3: ");
3506
        goto end;
3507
    }
3508
    ssn.client.next_seq = 17;
3509
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3510
        printf("failed to add segment 4: ");
3511
        goto end;
3512
    }
3513
    ssn.client.next_seq = 22;
3514
3515
    p->tcph->th_seq = htonl(17);
3516
    ret = 1;
3517
end:
3518
    FLOW_DESTROY(&f);
3519
    UTHFreePacket(p);
3520
    StreamTcpUTClearSession(&ssn);
3521
    StreamTcpUTDeinit(ra_ctx);
3522
    return ret;
3523
}
3524
3525
/** \test 3 in order segments, then reassemble, add one more and reassemble again.
3526
 *        test the sliding window reassembly with a small window size so that we
3527
 *        cutting off at the start (left edge) with small packet overlap.
3528
 */
3529
static int StreamTcpReassembleInlineTest04(void)
3530
{
3531
    int ret = 0;
3532
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3533
    ThreadVars tv;
3534
    TcpSession ssn;
3535
    Flow f;
3536
3537
    memset(&tv, 0x00, sizeof(tv));
3538
3539
    StreamTcpUTInit(&ra_ctx);
3540
    StreamTcpUTInitInline();
3541
    StreamTcpUTSetupSession(&ssn);
3542
    StreamTcpUTSetupStream(&ssn.client, 1);
3543
    FLOW_INITIALIZE(&f);
3544
3545
    stream_config.reassembly_toserver_chunk_size = 16;
3546
3547
    uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3548
    Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3549
    if (p == NULL) {
3550
        printf("couldn't get a packet: ");
3551
        goto end;
3552
    }
3553
    p->tcph->th_seq = htonl(12);
3554
    p->flow = &f;
3555
    p->flowflags |= FLOW_PKT_TOSERVER;
3556
3557
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1) {
3558
        printf("failed to add segment 1: ");
3559
        goto end;
3560
    }
3561
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1) {
3562
        printf("failed to add segment 2: ");
3563
        goto end;
3564
    }
3565
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3566
        printf("failed to add segment 3: ");
3567
        goto end;
3568
    }
3569
    ssn.client.next_seq = 17;
3570
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3571
        printf("failed to add segment 4: ");
3572
        goto end;
3573
    }
3574
    ssn.client.next_seq = 22;
3575
3576
    p->tcph->th_seq = htonl(17);
3577
    ret = 1;
3578
end:
3579
    FLOW_DESTROY(&f);
3580
    UTHFreePacket(p);
3581
    StreamTcpUTClearSession(&ssn);
3582
    StreamTcpUTDeinit(ra_ctx);
3583
    return ret;
3584
}
3585
3586
/** \test 3 in order segments, then reassemble, add one more and reassemble again.
3587
 *        test the sliding window reassembly with a small window size so that we
3588
 *        cutting off at the start (left edge). Test if the first segment is
3589
 *        removed from the list.
3590
 */
3591
static int StreamTcpReassembleInlineTest08(void)
3592
{
3593
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3594
    ThreadVars tv;
3595
    memset(&tv, 0x00, sizeof(tv));
3596
    TcpSession ssn;
3597
    Flow f;
3598
    StreamTcpUTInit(&ra_ctx);
3599
    StreamTcpUTInitInline();
3600
    StreamTcpUTSetupSession(&ssn);
3601
    StreamTcpUTSetupStream(&ssn.client, 1);
3602
    FLOW_INITIALIZE(&f);
3603
3604
    stream_config.reassembly_toserver_chunk_size = 15;
3605
    f.protoctx = &ssn;
3606
3607
    uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3608
    Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3609
    FAIL_IF(p == NULL);
3610
    p->tcph->th_seq = htonl(12);
3611
    p->flow = &f;
3612
    p->flowflags |= FLOW_PKT_TOSERVER;
3613
3614
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1);
3615
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1);
3616
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3617
    ssn.client.next_seq = 17;
3618
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
3619
    ssn.client.next_seq = 22;
3620
    p->tcph->th_seq = htonl(17);
3621
    StreamTcpPruneSession(&f, STREAM_TOSERVER);
3622
3623
    TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3624
    FAIL_IF_NULL(seg);
3625
    FAIL_IF_NOT(seg->seq == 2);
3626
3627
    FLOW_DESTROY(&f);
3628
    UTHFreePacket(p);
3629
    StreamTcpUTClearSession(&ssn);
3630
    StreamTcpUTDeinit(ra_ctx);
3631
    PASS;
3632
}
3633
3634
/** \test 3 in order segments, then reassemble, add one more and reassemble again.
3635
 *        test the sliding window reassembly with a small window size so that we
3636
 *        cutting off at the start (left edge). Test if the first segment is
3637
 *        removed from the list.
3638
 */
3639
static int StreamTcpReassembleInlineTest09(void)
3640
{
3641
    int ret = 0;
3642
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3643
    ThreadVars tv;
3644
    TcpSession ssn;
3645
    Flow f;
3646
3647
    memset(&tv, 0x00, sizeof(tv));
3648
3649
    StreamTcpUTInit(&ra_ctx);
3650
    StreamTcpUTInitInline();
3651
    StreamTcpUTSetupSession(&ssn);
3652
    StreamTcpUTSetupStream(&ssn.client, 1);
3653
    FLOW_INITIALIZE(&f);
3654
3655
    stream_config.reassembly_toserver_chunk_size = 20;
3656
3657
    uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3658
    Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3659
    if (p == NULL) {
3660
        printf("couldn't get a packet: ");
3661
        goto end;
3662
    }
3663
    p->tcph->th_seq = htonl(17);
3664
    p->flow = &f;
3665
    p->flowflags |= FLOW_PKT_TOSERVER;
3666
3667
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1) {
3668
        printf("failed to add segment 1: ");
3669
        goto end;
3670
    }
3671
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1) {
3672
        printf("failed to add segment 2: ");
3673
        goto end;
3674
    }
3675
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3676
        printf("failed to add segment 3: ");
3677
        goto end;
3678
    }
3679
    ssn.client.next_seq = 12;
3680
    ssn.client.last_ack = 10;
3681
3682
    /* close the GAP and see if we properly reassemble and update base_seq */
3683
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3684
        printf("failed to add segment 4: ");
3685
        goto end;
3686
    }
3687
    ssn.client.next_seq = 22;
3688
3689
    p->tcph->th_seq = htonl(12);
3690
3691
    TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3692
    FAIL_IF_NULL(seg);
3693
    FAIL_IF_NOT(seg->seq == 2);
3694
3695
    ret = 1;
3696
end:
3697
    FLOW_DESTROY(&f);
3698
    UTHFreePacket(p);
3699
    StreamTcpUTClearSession(&ssn);
3700
    StreamTcpUTDeinit(ra_ctx);
3701
    return ret;
3702
}
3703
3704
/** \test App Layer reassembly.
3705
 */
3706
static int StreamTcpReassembleInlineTest10(void)
3707
{
3708
    int ret = 0;
3709
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3710
    ThreadVars tv;
3711
    TcpSession ssn;
3712
    Flow *f = NULL;
3713
    Packet *p = NULL;
3714
3715
    memset(&tv, 0x00, sizeof(tv));
3716
3717
    StreamTcpUTInit(&ra_ctx);
3718
    StreamTcpUTInitInline();
3719
    StreamTcpUTSetupSession(&ssn);
3720
    StreamTcpUTSetupStream(&ssn.server, 1);
3721
    ssn.server.last_ack = 2;
3722
    StreamTcpUTSetupStream(&ssn.client, 1);
3723
    ssn.client.last_ack = 2;
3724
    ssn.data_first_seen_dir = STREAM_TOSERVER;
3725
3726
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
3727
    if (f == NULL)
3728
        goto end;
3729
    f->protoctx = &ssn;
3730
    f->proto = IPPROTO_TCP;
3731
3732
    uint8_t stream_payload1[] = "GE";
3733
    uint8_t stream_payload2[] = "T /";
3734
    uint8_t stream_payload3[] = "HTTP/1.0\r\n\r\n";
3735
3736
    p = UTHBuildPacketReal(stream_payload3, 12, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3737
    if (p == NULL) {
3738
        printf("couldn't get a packet: ");
3739
        goto end;
3740
    }
3741
    p->tcph->th_seq = htonl(7);
3742
    p->flow = f;
3743
    p->flowflags = FLOW_PKT_TOSERVER;
3744
3745
    if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client,  2, stream_payload1, 2) == -1) {
3746
        printf("failed to add segment 1: ");
3747
        goto end;
3748
    }
3749
    ssn.client.next_seq = 4;
3750
3751
    int r = StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET);
3752
    if (r < 0) {
3753
        printf("StreamTcpReassembleAppLayer failed: ");
3754
        goto end;
3755
    }
3756
3757
    /* ssn.server.ra_app_base_seq should be isn here. */
3758
    if (ssn.client.base_seq != 2 || ssn.client.base_seq != ssn.client.isn+1) {
3759
        printf("expected ra_app_base_seq 1, got %u: ", ssn.client.base_seq);
3760
        goto end;
3761
    }
3762
3763
    if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client,  4, stream_payload2, 3) == -1) {
3764
        printf("failed to add segment 2: ");
3765
        goto end;
3766
    }
3767
    if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client,  7, stream_payload3, 12) == -1) {
3768
        printf("failed to add segment 3: ");
3769
        goto end;
3770
    }
3771
    ssn.client.next_seq = 19;
3772
3773
    r = StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET);
3774
    if (r < 0) {
3775
        printf("StreamTcpReassembleAppLayer failed: ");
3776
        goto end;
3777
    }
3778
3779
    FAIL_IF_NOT(STREAM_APP_PROGRESS(&ssn.client) == 17);
3780
3781
    ret = 1;
3782
end:
3783
    UTHFreePacket(p);
3784
    StreamTcpUTClearSession(&ssn);
3785
    StreamTcpUTDeinit(ra_ctx);
3786
    UTHFreeFlow(f);
3787
    return ret;
3788
}
3789
3790
/** \test test insert with overlap
3791
 */
3792
static int StreamTcpReassembleInsertTest01(void)
3793
{
3794
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3795
    ThreadVars tv;
3796
    TcpSession ssn;
3797
    Flow f;
3798
3799
    memset(&tv, 0x00, sizeof(tv));
3800
3801
    StreamTcpUTInit(&ra_ctx);
3802
    StreamTcpUTSetupSession(&ssn);
3803
    StreamTcpUTSetupStream(&ssn.client, 1);
3804
    ssn.client.os_policy = OS_POLICY_LAST;
3805
    FLOW_INITIALIZE(&f);
3806
3807
    uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3808
    Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3809
    FAIL_IF(p == NULL);
3810
    p->tcph->th_seq = htonl(12);
3811
    p->flow = &f;
3812
3813
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1);
3814
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1);
3815
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 14, 'D', 2) == -1);
3816
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 16, 'D', 6) == -1);
3817
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3818
    ssn.client.next_seq = 21;
3819
3820
    FLOW_DESTROY(&f);
3821
    UTHFreePacket(p);
3822
    StreamTcpUTClearSession(&ssn);
3823
    StreamTcpUTDeinit(ra_ctx);
3824
    PASS;
3825
}
3826
3827
/** \test test insert with overlaps
3828
 */
3829
static int StreamTcpReassembleInsertTest02(void)
3830
{
3831
    int ret = 0;
3832
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3833
    ThreadVars tv;
3834
    TcpSession ssn;
3835
3836
    memset(&tv, 0x00, sizeof(tv));
3837
3838
    StreamTcpUTInit(&ra_ctx);
3839
    StreamTcpUTSetupSession(&ssn);
3840
    StreamTcpUTSetupStream(&ssn.client, 1);
3841
3842
    int i;
3843
    for (i = 2; i < 10; i++) {
3844
        int len;
3845
        len = i % 2;
3846
        if (len == 0)
3847
            len = 1;
3848
        int seq;
3849
        seq = i * 10;
3850
        if (seq < 2)
3851
            seq = 2;
3852
3853
        if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  seq, 'A', len) == -1) {
3854
            printf("failed to add segment 1: ");
3855
            goto end;
3856
        }
3857
    }
3858
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'B', 1024) == -1) {
3859
        printf("failed to add segment 2: ");
3860
        goto end;
3861
    }
3862
3863
    ret = 1;
3864
end:
3865
    StreamTcpUTClearSession(&ssn);
3866
    StreamTcpUTDeinit(ra_ctx);
3867
    return ret;
3868
}
3869
3870
/** \test test insert with overlaps
3871
 */
3872
static int StreamTcpReassembleInsertTest03(void)
3873
{
3874
    int ret = 0;
3875
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3876
    ThreadVars tv;
3877
    TcpSession ssn;
3878
3879
    memset(&tv, 0x00, sizeof(tv));
3880
3881
    StreamTcpUTInit(&ra_ctx);
3882
    StreamTcpUTSetupSession(&ssn);
3883
    StreamTcpUTSetupStream(&ssn.client, 1);
3884
3885
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 1024) == -1) {
3886
        printf("failed to add segment 2: ");
3887
        goto end;
3888
    }
3889
3890
    int i;
3891
    for (i = 2; i < 10; i++) {
3892
        int len;
3893
        len = i % 2;
3894
        if (len == 0)
3895
            len = 1;
3896
        int seq;
3897
        seq = i * 10;
3898
        if (seq < 2)
3899
            seq = 2;
3900
3901
        if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  seq, 'B', len) == -1) {
3902
            printf("failed to add segment 2: ");
3903
            goto end;
3904
        }
3905
    }
3906
    ret = 1;
3907
end:
3908
    StreamTcpUTClearSession(&ssn);
3909
    StreamTcpUTDeinit(ra_ctx);
3910
    return ret;
3911
}
3912
3913
#include "tests/stream-tcp-reassemble.c"
3914
#endif /* UNITTESTS */
3915
3916
/** \brief  The Function Register the Unit tests to test the reassembly engine
3917
 *          for various OS policies.
3918
 */
3919
3920
void StreamTcpReassembleRegisterTests(void)
3921
0
{
3922
#ifdef UNITTESTS
3923
    UtRegisterTest("StreamTcpReassembleTest25 -- Gap at Start Reassembly Test",
3924
                   StreamTcpReassembleTest25);
3925
    UtRegisterTest("StreamTcpReassembleTest26 -- Gap at middle Reassembly Test",
3926
                   StreamTcpReassembleTest26);
3927
    UtRegisterTest("StreamTcpReassembleTest27 -- Gap at after  Reassembly Test",
3928
                   StreamTcpReassembleTest27);
3929
    UtRegisterTest("StreamTcpReassembleTest28 -- Gap at Start IDS missed packet Reassembly Test",
3930
                   StreamTcpReassembleTest28);
3931
    UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test",
3932
                   StreamTcpReassembleTest29);
3933
    UtRegisterTest("StreamTcpReassembleTest33 -- Bug test",
3934
                   StreamTcpReassembleTest33);
3935
    UtRegisterTest("StreamTcpReassembleTest34 -- Bug test",
3936
                   StreamTcpReassembleTest34);
3937
    UtRegisterTest("StreamTcpReassembleTest39 -- app proto test",
3938
                   StreamTcpReassembleTest39);
3939
    UtRegisterTest("StreamTcpReassembleTest40 -- app proto test",
3940
                   StreamTcpReassembleTest40);
3941
    UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test",
3942
                   StreamTcpReassembleTest44);
3943
    UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test",
3944
                   StreamTcpReassembleTest45);
3945
    UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test",
3946
                   StreamTcpReassembleTest46);
3947
    UtRegisterTest("StreamTcpReassembleTest47 -- TCP Sequence Wraparound Test",
3948
                   StreamTcpReassembleTest47);
3949
3950
    UtRegisterTest("StreamTcpReassembleInlineTest01 -- inline RAW ra",
3951
                   StreamTcpReassembleInlineTest01);
3952
    UtRegisterTest("StreamTcpReassembleInlineTest02 -- inline RAW ra 2",
3953
                   StreamTcpReassembleInlineTest02);
3954
    UtRegisterTest("StreamTcpReassembleInlineTest03 -- inline RAW ra 3",
3955
                   StreamTcpReassembleInlineTest03);
3956
    UtRegisterTest("StreamTcpReassembleInlineTest04 -- inline RAW ra 4",
3957
                   StreamTcpReassembleInlineTest04);
3958
    UtRegisterTest("StreamTcpReassembleInlineTest08 -- inline RAW ra 8 cleanup",
3959
                   StreamTcpReassembleInlineTest08);
3960
    UtRegisterTest("StreamTcpReassembleInlineTest09 -- inline RAW ra 9 GAP cleanup",
3961
                   StreamTcpReassembleInlineTest09);
3962
3963
    UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10",
3964
                   StreamTcpReassembleInlineTest10);
3965
3966
    UtRegisterTest("StreamTcpReassembleInsertTest01 -- insert with overlap",
3967
                   StreamTcpReassembleInsertTest01);
3968
    UtRegisterTest("StreamTcpReassembleInsertTest02 -- insert with overlap",
3969
                   StreamTcpReassembleInsertTest02);
3970
    UtRegisterTest("StreamTcpReassembleInsertTest03 -- insert with overlap",
3971
                   StreamTcpReassembleInsertTest03);
3972
3973
    StreamTcpInlineRegisterTests();
3974
    StreamTcpUtilRegisterTests();
3975
    StreamTcpListRegisterTests();
3976
    StreamTcpReassembleRawRegisterTests();
3977
#endif /* UNITTESTS */
3978
0
}