Coverage Report

Created: 2025-07-23 07:29

/src/suricata7/src/stream-tcp-reassemble.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2007-2022 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
10.4M
{
93
10.4M
    return g_tcp_session_dump_enabled == 1;
94
10.4M
}
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
71
{
107
71
    SC_ATOMIC_INIT(ra_memuse);
108
71
}
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.10M
{
118
1.10M
    (void) SC_ATOMIC_ADD(ra_memuse, size);
119
1.10M
    SCLogDebug("REASSEMBLY %"PRIu64", incr %"PRIu64, StreamTcpReassembleMemuseGlobalCounter(), size);
120
1.10M
    return;
121
1.10M
}
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.03M
{
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.03M
    (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.03M
    SCLogDebug("REASSEMBLY %"PRIu64", decr %"PRIu64, StreamTcpReassembleMemuseGlobalCounter(), size);
147
1.03M
    return;
148
1.03M
}
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
3.83M
{
166
#ifdef DEBUG
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
3.83M
    uint64_t memcapcopy = SC_ATOMIC_GET(stream_config.reassembly_memcap);
174
3.83M
    if (memcapcopy == 0 ||
175
3.83M
        (uint64_t)((uint64_t)size + SC_ATOMIC_GET(ra_memuse)) <= memcapcopy)
176
3.83M
        return 1;
177
0
    return 0;
178
3.83M
}
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.37M
{
213
1.37M
    if (StreamTcpReassembleCheckMemcap(n * size) == 0) {
214
0
        sc_errno = SC_ELIMIT;
215
0
        return NULL;
216
0
    }
217
1.37M
    void *ptr = SCCalloc(n, size);
218
1.37M
    if (ptr == NULL) {
219
0
        sc_errno = SC_ENOMEM;
220
0
        return NULL;
221
0
    }
222
1.37M
    StreamTcpReassembleIncrMemuse(n * size);
223
1.37M
    return ptr;
224
1.37M
}
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
284k
{
231
284k
    if (size > orig_size) {
232
280k
        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
280k
    }
238
284k
    void *nptr = SCRealloc(optr, size);
239
284k
    if (nptr == NULL) {
240
0
        SCLogDebug("realloc fail");
241
0
        sc_errno = SC_ENOMEM;
242
0
        return NULL;
243
0
    }
244
284k
    if (size > orig_size) {
245
280k
        StreamTcpReassembleIncrMemuse(size - orig_size);
246
280k
    } else {
247
3.48k
        StreamTcpReassembleDecrMemuse(orig_size - size);
248
3.48k
    }
249
284k
    return nptr;
250
284k
}
251
252
/*
253
    void (*Free)(void *ptr, size_t size);
254
*/
255
static void ReassembleFree(void *ptr, size_t size)
256
1.37M
{
257
1.37M
    SCFree(ptr);
258
1.37M
    StreamTcpReassembleDecrMemuse(size);
259
1.37M
}
260
261
/** \brief alloc a tcp segment pool entry */
262
static void *TcpSegmentPoolAlloc(void)
263
1.09M
{
264
1.09M
    SCLogDebug("segment alloc");
265
1.09M
    if (StreamTcpReassembleCheckMemcap((uint32_t)sizeof(TcpSegment)) == 0) {
266
0
        return NULL;
267
0
    }
268
269
1.09M
    TcpSegment *seg = NULL;
270
271
1.09M
    seg = SCMalloc(sizeof (TcpSegment));
272
1.09M
    if (unlikely(seg == NULL))
273
0
        return NULL;
274
275
1.09M
    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
1.09M
    } else {
305
1.09M
        seg->pcap_hdr_storage = NULL;
306
1.09M
    }
307
308
1.09M
    return seg;
309
1.09M
}
310
311
static int TcpSegmentPoolInit(void *data, void *initdata)
312
1.09M
{
313
1.09M
    TcpSegment *seg = (TcpSegment *) data;
314
1.09M
    TcpSegmentPcapHdrStorage *pcap_hdr;
315
316
1.09M
    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.09M
    memset(seg, 0, sizeof (TcpSegment));
321
322
1.09M
    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.09M
    } else {
331
1.09M
        if (StreamTcpReassembleCheckMemcap((uint32_t)sizeof(TcpSegment)) == 0) {
332
0
            return 0;
333
0
        }
334
1.09M
    }
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.09M
    StreamTcpReassembleIncrMemuse((uint32_t)sizeof(TcpSegment));
345
1.09M
    return 1;
346
1.09M
}
347
348
/** \brief clean up a tcp segment pool entry */
349
static void TcpSegmentPoolCleanup(void *ptr)
350
1.08M
{
351
1.08M
    if (ptr == NULL)
352
0
        return;
353
354
1.08M
    TcpSegment *seg = (TcpSegment *)ptr;
355
1.08M
    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
1.08M
    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
1.08M
}
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
8.24M
{
383
8.24M
    if (seg == NULL)
384
0
        return;
385
386
8.24M
    if (seg->pcap_hdr_storage && seg->pcap_hdr_storage->pktlen) {
387
0
        seg->pcap_hdr_storage->pktlen = 0;
388
0
    }
389
390
8.24M
    StreamTcpThreadCacheReturnSegment(seg);
391
8.24M
}
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
809k
{
400
809k
    TcpSegment *seg = NULL, *safe = NULL;
401
809k
    RB_FOREACH_SAFE(seg, TCPSEG, &stream->seg_tree, safe)
402
4.35M
    {
403
4.35M
        RB_REMOVE(TCPSEG, &stream->seg_tree, seg);
404
4.35M
        StreamTcpSegmentReturntoPool(seg);
405
4.35M
    }
406
809k
}
407
408
static inline uint64_t GetAbsLastAck(const TcpStream *stream)
409
8.08M
{
410
8.08M
    if (STREAM_LASTACK_GT_BASESEQ(stream)) {
411
7.63M
        return STREAM_BASE_OFFSET(stream) + (stream->last_ack - stream->base_seq);
412
7.63M
    } else {
413
450k
        return STREAM_BASE_OFFSET(stream);
414
450k
    }
415
8.08M
}
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
208
{
425
208
    uint64_t right_edge = STREAM_BASE_OFFSET(stream) + stream->segs_right_edge - stream->base_seq;
426
208
    if (!eof && StreamTcpInlineMode() == FALSE) {
427
176
        right_edge = MIN(GetAbsLastAck(stream), right_edge);
428
176
    }
429
208
    return right_edge;
430
208
}
431
432
uint64_t StreamTcpGetUsable(const TcpStream *stream, const bool eof)
433
2.34M
{
434
2.34M
    uint64_t right_edge = StreamingBufferGetConsecutiveDataRightEdge(&stream->sb);
435
2.34M
    if (!eof && StreamTcpInlineMode() == FALSE) {
436
2.17M
        right_edge = MIN(GetAbsLastAck(stream), right_edge);
437
2.17M
    }
438
2.34M
    return right_edge;
439
2.34M
}
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
331k
{
455
331k
    if (f->protoctx == NULL)
456
0
        return;
457
458
331k
    TcpSession *ssn = (TcpSession *)f->protoctx;
459
331k
    StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client);
460
331k
    StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server);
461
331k
    StreamTcpDisableAppLayerReassembly(ssn);
462
331k
    if (f->alparser) {
463
70.9k
        AppLayerParserStateSetFlag(f->alparser,
464
70.9k
                (APP_LAYER_PARSER_EOF_TS|APP_LAYER_PARSER_EOF_TC));
465
70.9k
    }
466
331k
}
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
71
{
531
    /* init the memcap/use tracker */
532
71
    StreamTcpReassembleInitMemuse();
533
534
71
    if (StreamTcpReassemblyConfig(quiet) < 0)
535
0
        return -1;
536
537
#ifdef DEBUG
538
    SCMutexInit(&segment_pool_memuse_mutex, NULL);
539
#endif
540
71
    StatsRegisterGlobalCounter("tcp.reassembly_memuse",
541
71
            StreamTcpReassembleMemuseGlobalCounter);
542
71
    return 0;
543
71
}
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
55.2M
{
626
55.2M
    if (p->flow != NULL && p->flow->protoctx != NULL) {
627
55.1M
        TcpSession *ssn = p->flow->protoctx;
628
55.1M
        TcpStream *stream;
629
55.1M
        if (p->flowflags & FLOW_PKT_TOSERVER) {
630
26.6M
            stream = &ssn->client;
631
28.4M
        } else {
632
28.4M
            stream = &ssn->server;
633
28.4M
        }
634
635
55.1M
        return (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) ? 1 : 0;
636
55.1M
    }
637
638
52.0k
    return 0;
639
55.2M
}
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
8.24M
{
655
8.24M
    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
8.24M
    if (ssn->reassembly_depth == 0) {
660
8.24M
        SCReturnUInt(size);
661
8.24M
    }
662
663
    /* if the final flag is set, we're not accepting anymore */
664
0
    if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
665
0
        SCReturnUInt(0);
666
0
    }
667
668
0
    uint64_t seg_depth;
669
0
    if (SEQ_GT(stream->base_seq, seq)) {
670
0
        if (SEQ_LEQ(seq+size, stream->base_seq)) {
671
0
            SCLogDebug("segment entirely before base_seq, weird: base %u, seq %u, re %u",
672
0
                    stream->base_seq, seq, seq+size);
673
0
            SCReturnUInt(0);
674
0
        }
675
676
0
        seg_depth = STREAM_BASE_OFFSET(stream) + size - (stream->base_seq - seq);
677
0
    } else {
678
0
        seg_depth = STREAM_BASE_OFFSET(stream) + ((seq + size) - stream->base_seq);
679
0
    }
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
0
    SCLogDebug("seq + size %u, base %u, seg_depth %"PRIu64" limit %u", (seq + size),
686
0
            stream->base_seq, seg_depth,
687
0
            ssn->reassembly_depth);
688
689
0
    if (seg_depth > (uint64_t)ssn->reassembly_depth) {
690
0
        SCLogDebug("STREAMTCP_STREAM_FLAG_DEPTH_REACHED");
691
0
        stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED;
692
0
        SCReturnUInt(0);
693
0
    }
694
0
    SCLogDebug("NOT STREAMTCP_STREAM_FLAG_DEPTH_REACHED");
695
0
    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
0
    if (SEQ_GEQ(seq, stream->isn) && SEQ_LT(seq, (stream->isn + ssn->reassembly_depth))) {
702
        /* packet (partly?) fits the depth window */
703
704
0
        if (SEQ_LEQ((seq + size),(stream->isn + 1 + ssn->reassembly_depth))) {
705
            /* complete fit */
706
0
            SCReturnUInt(size);
707
0
        } 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
0
    }
717
718
0
    SCReturnUInt(0);
719
0
}
720
721
uint32_t StreamDataAvailableForProtoDetect(TcpStream *stream)
722
341k
{
723
341k
    if (RB_EMPTY(&stream->sb.sbb_tree)) {
724
301k
        if (stream->sb.region.stream_offset != 0)
725
0
            return 0;
726
727
301k
        return stream->sb.region.buf_offset;
728
301k
    } else {
729
39.5k
        DEBUG_VALIDATE_BUG_ON(stream->sb.head == NULL);
730
39.5k
        DEBUG_VALIDATE_BUG_ON(stream->sb.sbb_size == 0);
731
39.5k
        return stream->sb.sbb_size;
732
39.5k
    }
733
341k
}
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
3.57M
{
748
3.57M
    SCEnter();
749
750
3.57M
    if (ssn->data_first_seen_dir == 0) {
751
116k
        if (PKT_IS_TOSERVER(p)) {
752
92.3k
            ssn->data_first_seen_dir = STREAM_TOSERVER;
753
92.3k
        } else {
754
24.2k
            ssn->data_first_seen_dir = STREAM_TOCLIENT;
755
24.2k
        }
756
116k
    }
757
758
    /* If the OS policy is not set then set the OS policy for this stream */
759
3.57M
    if (stream->os_policy == 0) {
760
147k
        StreamTcpSetOSPolicy(stream, p);
761
147k
    }
762
763
3.57M
    if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) &&
764
3.57M
        (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED)) {
765
1.24k
        SCLogDebug("ssn %p: both app and raw reassembly disabled, not reassembling", ssn);
766
1.24k
        SCReturnInt(0);
767
1.24k
    }
768
769
3.57M
    uint16_t *urg_offset;
770
3.57M
    if (PKT_IS_TOSERVER(p)) {
771
1.63M
        urg_offset = &ssn->urg_offset_ts;
772
1.94M
    } else {
773
1.94M
        urg_offset = &ssn->urg_offset_tc;
774
1.94M
    }
775
776
    /* segment sequence number, offset by previously accepted
777
     * URG OOB data. */
778
3.57M
    uint32_t seg_seq = TCP_GET_RAW_SEQ(p->tcph) - (*urg_offset);
779
3.57M
    uint8_t urg_data = 0;
780
781
    /* if stream_config.urgent_policy == TCP_STREAM_URGENT_DROP, we won't get here */
782
3.57M
    if (p->tcph->th_flags & TH_URG) {
783
83.0k
        const uint16_t urg_ptr = SCNtohs(p->tcph->th_urp);
784
83.0k
        if (urg_ptr > 0 && urg_ptr <= p->payload_len &&
785
83.0k
                (stream_config.urgent_policy == TCP_STREAM_URGENT_OOB ||
786
2.71k
                        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
83.0k
    }
821
822
3.57M
    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
3.57M
    uint32_t size = StreamTcpReassembleCheckDepth(ssn, stream, seg_seq, payload_len);
827
3.57M
    SCLogDebug("ssn %p: check depth returned %"PRIu32, ssn, size);
828
829
3.57M
    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
3.57M
    if (size == 0) {
836
0
        SCLogDebug("ssn %p: depth reached, not reassembling", ssn);
837
0
        SCReturnInt(0);
838
0
    }
839
840
3.57M
    DEBUG_VALIDATE_BUG_ON(size > payload_len);
841
3.57M
    if (size > payload_len)
842
0
        size = payload_len;
843
844
3.57M
    TcpSegment *seg = StreamTcpGetSegment(tv, ra_ctx);
845
3.57M
    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
3.57M
    DEBUG_VALIDATE_BUG_ON(size > UINT16_MAX);
853
3.57M
    TCP_SEG_LEN(seg) = (uint16_t)size;
854
    /* set SEQUENCE number, adjusted to any URG pointer offset */
855
3.57M
    seg->seq = seg_seq;
856
857
    /* HACK: for TFO SYN packets the seq for data starts at + 1 */
858
3.57M
    if (TCP_HAS_TFO(p) && p->payload_len && (p->tcph->th_flags & TH_SYN))
859
10
        seg->seq += 1;
860
861
    /* proto detection skipped, but now we do get data. Set event. */
862
3.57M
    if (RB_EMPTY(&stream->seg_tree) &&
863
3.57M
        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
3.57M
    int r = StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, seg, p, p->payload, payload_len);
870
3.57M
    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
3.57M
    SCReturnInt(0);
878
3.57M
}
879
880
static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream,
881
                                      Packet *p)
882
13.5M
{
883
13.5M
    uint8_t flag = 0;
884
885
13.5M
    if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) {
886
2.28M
        flag |= STREAM_START;
887
2.28M
    }
888
889
13.5M
    if (ssn->state == TCP_CLOSED) {
890
194k
        flag |= STREAM_EOF;
891
194k
    }
892
893
13.5M
    if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
894
2.87M
        flag |= STREAM_MIDSTREAM;
895
2.87M
    }
896
897
13.5M
    if (p->flags & PKT_PSEUDO_STREAM_END) {
898
317k
        flag |= STREAM_EOF;
899
317k
    }
900
901
13.5M
    if (&ssn->client == stream) {
902
6.26M
        flag |= STREAM_TOSERVER;
903
7.30M
    } else {
904
7.30M
        flag |= STREAM_TOCLIENT;
905
7.30M
    }
906
13.5M
    if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
907
0
        flag |= STREAM_DEPTH;
908
0
    }
909
13.5M
    return flag;
910
13.5M
}
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
255k
        if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
931
0
            SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_DEPTH_REACHED "
932
0
                    "is set, so not expecting any new data segments");
933
0
        }
934
255k
        if (stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW) {
935
255k
            SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_TRIGGER_RAW is set");
936
255k
        }
937
255k
        if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) {
938
2.77k
            SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED is set, "
939
2.77k
                    "so no new segments will be considered");
940
2.77k
        }
941
255k
        SCReturnInt(1);
942
255k
    }
943
2.09M
#undef STREAMTCP_STREAM_FLAG_FLUSH_FLAGS
944
945
    /* some states mean we reassemble no matter how much data we have */
946
2.09M
    if (ssn->state > TCP_TIME_WAIT)
947
237k
        SCReturnInt(1);
948
949
1.85M
    if (p->flags & PKT_PSEUDO_STREAM_END)
950
29.1k
        SCReturnInt(1);
951
952
1.82M
    const uint64_t last_ack_abs = GetAbsLastAck(stream);
953
1.82M
    int64_t diff = last_ack_abs - STREAM_RAW_PROGRESS(stream);
954
1.82M
    int64_t chunk_size = PKT_IS_TOSERVER(p) ? (int64_t)stream_config.reassembly_toserver_chunk_size
955
1.82M
                                            : (int64_t)stream_config.reassembly_toclient_chunk_size;
956
957
    /* check if we have enough data to do raw reassembly */
958
1.82M
    if (chunk_size <= diff) {
959
173k
        SCReturnInt(1);
960
1.65M
    } else {
961
1.65M
        SCLogDebug("%s min chunk len not yet reached: "
962
1.65M
                   "last_ack %" PRIu32 ", ra_raw_base_seq %" PRIu32 ", %" PRIu32 " < "
963
1.65M
                   "%" PRIi64,
964
1.65M
                PKT_IS_TOSERVER(p) ? "toserver" : "toclient", stream->last_ack, stream->base_seq,
965
1.65M
                (stream->last_ack - stream->base_seq), chunk_size);
966
1.65M
        SCReturnInt(0);
967
1.65M
    }
968
969
1.82M
    SCReturnInt(0);
970
1.82M
}
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
381k
{
977
381k
    const TcpStream *stream = NULL;
978
#ifdef DEBUG
979
    const char *dirstr = NULL;
980
#endif
981
381k
    if (direction == STREAM_TOSERVER) {
982
190k
        stream = &ssn->client;
983
#ifdef DEBUG
984
        dirstr = "client";
985
#endif
986
190k
    } else {
987
190k
        stream = &ssn->server;
988
#ifdef DEBUG
989
        dirstr = "server";
990
#endif
991
190k
    }
992
381k
    int use_app = 1;
993
381k
    int use_raw = 1;
994
995
381k
    if (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) {
996
        // app is dead
997
31.4k
        use_app = 0;
998
31.4k
    }
999
1000
381k
    if (stream->flags & STREAMTCP_STREAM_FLAG_DISABLE_RAW) {
1001
        // raw is dead
1002
251k
        use_raw = 0;
1003
251k
    }
1004
381k
    if (use_raw) {
1005
129k
        const uint64_t right_edge =
1006
129k
                STREAM_BASE_OFFSET(stream) + stream->segs_right_edge - stream->base_seq;
1007
129k
        SCLogDebug("%s: app %" PRIu64 " (use: %s), raw %" PRIu64
1008
129k
                   " (use: %s). Stream right edge: %" PRIu64,
1009
129k
                dirstr, STREAM_APP_PROGRESS(stream), use_app ? "yes" : "no",
1010
129k
                STREAM_RAW_PROGRESS(stream), use_raw ? "yes" : "no", right_edge);
1011
129k
        if (right_edge > STREAM_RAW_PROGRESS(stream)) {
1012
114k
            SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION", dirstr);
1013
114k
            return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
1014
114k
        }
1015
129k
    }
1016
267k
    if (use_app) {
1017
241k
        const uint64_t right_edge = StreamingBufferGetConsecutiveDataRightEdge(&stream->sb);
1018
241k
        SCLogDebug("%s: app %" PRIu64 " (use: %s), raw %" PRIu64
1019
241k
                   " (use: %s). Stream right edge: %" PRIu64,
1020
241k
                dirstr, STREAM_APP_PROGRESS(stream), use_app ? "yes" : "no",
1021
241k
                STREAM_RAW_PROGRESS(stream), use_raw ? "yes" : "no", right_edge);
1022
241k
        if (right_edge > STREAM_APP_PROGRESS(stream)) {
1023
58.6k
            SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION", dirstr);
1024
58.6k
            return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
1025
58.6k
        }
1026
241k
    }
1027
1028
208k
    SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NONE", dirstr);
1029
208k
    return STREAM_HAS_UNPROCESSED_SEGMENTS_NONE;
1030
267k
}
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
145k
{
1099
145k
    StreamingBufferBlock *nblk = SBB_RB_NEXT(cur_blk);
1100
145k
    if (nblk && (cur_blk->offset + cur_blk->len < nblk->offset) &&
1101
145k
            GetAbsLastAck(stream) > (cur_blk->offset + cur_blk->len)) {
1102
13.7k
        return true;
1103
13.7k
    }
1104
131k
    return false;
1105
145k
}
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
13.1M
{
1119
13.1M
    const uint8_t *mydata;
1120
13.1M
    uint32_t mydata_len;
1121
13.1M
    bool gap_ahead = false;
1122
1123
13.1M
    if (RB_EMPTY(&stream->sb.sbb_tree)) {
1124
12.0M
        SCLogDebug("getting one blob");
1125
1126
12.0M
        StreamingBufferGetDataAtOffset(&stream->sb, &mydata, &mydata_len, offset);
1127
1128
12.0M
        *data = mydata;
1129
12.0M
        *data_len = mydata_len;
1130
12.0M
    } else {
1131
1.13M
        SCLogDebug("block mode");
1132
1.13M
        StreamingBufferBlock key = { .offset = offset, .len = 0 };
1133
1.13M
        StreamingBufferBlock *blk = SBB_RB_FIND_INCLUSIVE((struct SBB *)&stream->sb.sbb_tree, &key);
1134
1.13M
        if (blk == NULL) {
1135
313k
            *data = NULL;
1136
313k
            *data_len = 0;
1137
313k
            return false;
1138
313k
        }
1139
817k
        SCLogDebug("blk %p blk->offset %" PRIu64 ", blk->len %u", blk, blk->offset, blk->len);
1140
1141
        /* block at expected offset */
1142
817k
        if (blk->offset == offset) {
1143
221k
            SCLogDebug("blk at offset");
1144
1145
221k
            StreamingBufferSBBGetData(&stream->sb, blk, data, data_len);
1146
221k
            BUG_ON(blk->len != *data_len);
1147
1148
221k
            gap_ahead = check_for_gap && GapAhead(stream, blk);
1149
1150
        /* block past out offset */
1151
595k
        } else if (blk->offset > offset) {
1152
276k
            SCLogDebug("gap, want data at offset %"PRIu64", "
1153
276k
                    "got data at %"PRIu64". GAP of size %"PRIu64,
1154
276k
                    offset, blk->offset, blk->offset - offset);
1155
276k
            *data = NULL;
1156
276k
            *data_len = blk->offset - offset;
1157
1158
        /* block starts before offset, but ends after */
1159
319k
        } else if (offset > blk->offset && offset <= (blk->offset + blk->len)) {
1160
319k
            SCLogDebug("get data from offset %"PRIu64". SBB %"PRIu64"/%u",
1161
319k
                    offset, blk->offset, blk->len);
1162
319k
            StreamingBufferSBBGetDataAtOffset(&stream->sb, blk, data, data_len, offset);
1163
319k
            SCLogDebug("data %p, data_len %u", *data, *data_len);
1164
1165
319k
            gap_ahead = check_for_gap && GapAhead(stream, blk);
1166
1167
319k
        } else {
1168
0
            *data = NULL;
1169
0
            *data_len = 0;
1170
0
        }
1171
817k
    }
1172
12.8M
    return gap_ahead;
1173
13.1M
}
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
98.7k
{
1182
98.7k
    const uint64_t app_progress = STREAM_APP_PROGRESS(stream);
1183
98.7k
    const int ackadded = (ssn->state >= TCP_FIN_WAIT1) ? 1 : 0;
1184
98.7k
    const uint64_t last_ack_abs = GetAbsLastAck(stream) - (uint64_t)ackadded;
1185
1186
98.7k
    SCLogDebug("last_ack %u abs %" PRIu64, stream->last_ack, last_ack_abs);
1187
98.7k
    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
98.7k
    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
95.6k
        if (SEQ_GT(stream->last_ack, stream->next_seq)) {
1196
11.8k
            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
11.8k
            } else {
1202
11.8k
                const uint64_t next_seq_abs =
1203
11.8k
                        STREAM_BASE_OFFSET(stream) + (stream->next_seq - stream->base_seq);
1204
11.8k
                const StreamingBufferBlock *blk = stream->sb.head;
1205
11.8k
                if (blk->offset > next_seq_abs && blk->offset < last_ack_abs) {
1206
                    /* ack'd data after the gap */
1207
664
                    SCLogDebug("packet %" PRIu64 ": GAP. "
1208
664
                               "next_seq %u < last_ack %u, but ACK'd data beyond gap.",
1209
664
                            p->pcap_cnt, stream->next_seq, stream->last_ack);
1210
664
                    return true;
1211
664
                }
1212
11.8k
            }
1213
11.8k
        }
1214
1215
94.9k
        SCLogDebug("packet %" PRIu64 ": GAP! "
1216
94.9k
                   "last_ack_abs %" PRIu64 " > app_progress %" PRIu64 ", "
1217
94.9k
                   "but we have no data.",
1218
94.9k
                p->pcap_cnt, last_ack_abs, app_progress);
1219
94.9k
        return true;
1220
95.6k
    }
1221
3.09k
    SCLogDebug("packet %"PRIu64": no GAP. "
1222
3.09k
            "last_ack_abs %"PRIu64" <= app_progress %"PRIu64,
1223
3.09k
            p->pcap_cnt, last_ack_abs, app_progress);
1224
3.09k
    return false;
1225
98.7k
}
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
5.48M
{
1231
5.48M
    uint32_t adjusted = data_len;
1232
1233
    /* get window of data that is acked */
1234
5.48M
    if (StreamTcpInlineMode() == FALSE) {
1235
5.48M
        SCLogDebug("ssn->state %s", StreamTcpStateAsString(ssn->state));
1236
5.48M
        if (data_len == 0 || ((ssn->state < TCP_CLOSED ||
1237
2.84M
                                      (ssn->state == TCP_CLOSED &&
1238
48.8k
                                              (ssn->flags & STREAMTCP_FLAG_CLOSED_BY_RST) != 0)) &&
1239
2.84M
                                     (p->flags & PKT_PSEUDO_STREAM_END))) {
1240
            // fall through, we use all available data
1241
2.77M
        } else {
1242
2.77M
            const uint64_t last_ack_abs = GetAbsLastAck(stream);
1243
2.77M
            DEBUG_VALIDATE_BUG_ON(app_progress > last_ack_abs);
1244
1245
            /* see if the buffer contains unack'd data as well */
1246
2.77M
            if (app_progress <= last_ack_abs && app_progress + data_len > last_ack_abs) {
1247
98.4k
                uint32_t check = data_len;
1248
98.4k
                adjusted = last_ack_abs - app_progress;
1249
98.4k
                BUG_ON(adjusted > check);
1250
98.4k
                SCLogDebug("data len adjusted to %u to make sure only ACK'd "
1251
98.4k
                        "data is considered", adjusted);
1252
98.4k
            }
1253
2.77M
        }
1254
5.48M
    }
1255
5.48M
    return adjusted;
1256
5.48M
}
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
10.0M
{
1268
10.0M
    uint64_t app_progress = STREAM_APP_PROGRESS(*stream);
1269
1270
10.0M
    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
10.0M
    const uint8_t *mydata;
1277
10.0M
    uint32_t mydata_len;
1278
10.0M
    bool last_was_gap = false;
1279
1280
13.1M
    while (1) {
1281
13.1M
        const uint8_t flags = StreamGetAppLayerFlags(ssn, *stream, p);
1282
13.1M
        bool check_for_gap_ahead = ((*stream)->data_required > 0);
1283
13.1M
        bool gap_ahead =
1284
13.1M
                GetAppBuffer(*stream, &mydata, &mydata_len, app_progress, check_for_gap_ahead);
1285
13.1M
        SCLogDebug("gap_ahead %s mydata_len %u", BOOL2STR(gap_ahead), mydata_len);
1286
13.1M
        if (last_was_gap && mydata_len == 0) {
1287
0
            break;
1288
0
        }
1289
13.1M
        last_was_gap = false;
1290
1291
        /* make sure to only deal with ACK'd data */
1292
13.1M
        mydata_len = AdjustToAcked(p, ssn, *stream, app_progress, mydata_len);
1293
13.1M
        DEBUG_VALIDATE_BUG_ON(mydata_len > (uint32_t)INT_MAX);
1294
13.1M
        if (mydata == NULL && mydata_len > 0 && CheckGap(ssn, *stream, p)) {
1295
211k
            SCLogDebug("sending GAP to app-layer (size: %u)", mydata_len);
1296
1297
211k
            int r = AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, NULL, mydata_len,
1298
211k
                    StreamGetAppLayerFlags(ssn, *stream, p) | STREAM_GAP, dir);
1299
211k
            AppLayerProfilingStore(ra_ctx->app_tctx, p);
1300
1301
211k
            StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP);
1302
211k
            (*stream)->flags |= STREAMTCP_STREAM_FLAG_HAS_GAP;
1303
211k
            StatsIncr(tv, ra_ctx->counter_tcp_reass_gap);
1304
211k
            ssn->flags |= STREAMTCP_FLAG_LOSSY_BE_LIBERAL;
1305
1306
            /* AppLayerHandleTCPData has likely updated progress. */
1307
211k
            const bool no_progress_update = (app_progress == STREAM_APP_PROGRESS(*stream));
1308
211k
            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
211k
            if ((*stream)->data_required > 0) {
1313
11.5k
                if ((*stream)->data_required > mydata_len) {
1314
5.08k
                    (*stream)->data_required -= mydata_len;
1315
6.44k
                } else {
1316
6.44k
                    (*stream)->data_required = 0;
1317
6.44k
                }
1318
11.5k
            }
1319
211k
            if (r < 0)
1320
143k
                return 0;
1321
67.9k
            if (no_progress_update)
1322
433
                break;
1323
67.5k
            last_was_gap = true;
1324
67.5k
            continue;
1325
1326
12.9M
        } else if (flags & STREAM_DEPTH) {
1327
0
            SCLogDebug("DEPTH");
1328
            // we're just called once with this flag, so make sure we pass it on
1329
0
            if (mydata == NULL && mydata_len > 0) {
1330
0
                mydata_len = 0;
1331
0
            }
1332
12.9M
        } else if (mydata == NULL || (mydata_len == 0 && ((flags & STREAM_EOF) == 0))) {
1333
7.08M
            SCLogDebug("GAP?1");
1334
            /* Possibly a gap, but no new data. */
1335
7.08M
            if ((p->flags & PKT_PSEUDO_STREAM_END) == 0 || ssn->state < TCP_CLOSED)
1336
7.06M
                SCReturnInt(0);
1337
1338
12.9k
            mydata = NULL;
1339
12.9k
            mydata_len = 0;
1340
12.9k
            SCLogDebug("%"PRIu64" got %p/%u", p->pcap_cnt, mydata, mydata_len);
1341
12.9k
            break;
1342
7.08M
        }
1343
5.85M
        DEBUG_VALIDATE_BUG_ON(mydata == NULL && mydata_len > 0);
1344
1345
5.85M
        SCLogDebug("stream %p data in buffer %p of len %u and offset %"PRIu64,
1346
5.85M
                *stream, &(*stream)->sb, mydata_len, app_progress);
1347
1348
5.85M
        if ((p->flags & PKT_PSEUDO_STREAM_END) == 0 || ssn->state < TCP_CLOSED) {
1349
5.81M
            SCLogDebug("GAP?2");
1350
5.81M
            if (mydata_len < (*stream)->data_required) {
1351
1.98M
                SCLogDebug("GAP?3 gap_head %s", BOOL2STR(gap_ahead));
1352
1.98M
                if (gap_ahead) {
1353
11.2k
                    SCLogDebug("GAP while expecting more data (expect %u, gap size %u)",
1354
11.2k
                            (*stream)->data_required, mydata_len);
1355
11.2k
                    (*stream)->app_progress_rel += mydata_len;
1356
11.2k
                    (*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.97M
                } else {
1360
1.97M
                    SCReturnInt(0);
1361
1.97M
                }
1362
11.2k
                app_progress = STREAM_APP_PROGRESS(*stream);
1363
11.2k
                continue;
1364
1.98M
            }
1365
5.81M
        }
1366
3.86M
        (*stream)->data_required = 0;
1367
1368
3.86M
        SCLogDebug("parser");
1369
        /* update the app-layer */
1370
3.86M
        (void)AppLayerHandleTCPData(
1371
3.86M
                tv, ra_ctx, p, p->flow, ssn, stream, (uint8_t *)mydata, mydata_len, flags, dir);
1372
3.86M
        AppLayerProfilingStore(ra_ctx->app_tctx, p);
1373
3.86M
        AppLayerFrameDump(p->flow);
1374
3.86M
        uint64_t new_app_progress = STREAM_APP_PROGRESS(*stream);
1375
3.86M
        if (new_app_progress == app_progress || FlowChangeProto(p->flow))
1376
801k
            break;
1377
3.06M
        app_progress = new_app_progress;
1378
3.06M
        if (flags & STREAM_DEPTH)
1379
0
            break;
1380
3.06M
    }
1381
1382
10.0M
    SCReturnInt(0);
1383
10.0M
}
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
5.16M
{
1401
5.16M
    SCEnter();
1402
1403
    /* this function can be directly called by app layer protocol
1404
     * detection. */
1405
5.16M
    if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) ||
1406
5.16M
        (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
1407
643k
        SCLogDebug("stream no reassembly flag set or app-layer disabled.");
1408
643k
        SCReturnInt(0);
1409
643k
    }
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
4.52M
    if (!STREAM_HAS_SEEN_DATA(stream) || STREAM_RIGHT_EDGE(stream) <= STREAM_APP_PROGRESS(stream))
1418
1.81M
    {
1419
        /* send an empty EOF msg if we have no segments but TCP state
1420
         * is beyond ESTABLISHED */
1421
1.81M
        if (ssn->state >= TCP_CLOSING || (p->flags & PKT_PSEUDO_STREAM_END)) {
1422
94.9k
            SCLogDebug("sending empty eof message");
1423
            /* send EOF to app layer */
1424
94.9k
            AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, &stream, NULL, 0,
1425
94.9k
                    StreamGetAppLayerFlags(ssn, stream, p), dir);
1426
94.9k
            AppLayerProfilingStore(ra_ctx->app_tctx, p);
1427
1428
94.9k
            SCReturnInt(0);
1429
94.9k
        }
1430
1.81M
    }
1431
1432
    /* with all that out of the way, lets update the app-layer */
1433
4.42M
    return ReassembleUpdateAppLayer(tv, ra_ctx, ssn, &stream, p, dir);
1434
4.52M
}
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
2.90M
{
1442
2.90M
    const uint8_t *mydata;
1443
2.90M
    uint32_t mydata_len;
1444
2.90M
    if (RB_EMPTY(&stream->sb.sbb_tree)) {
1445
556k
        SCLogDebug("getting one blob for offset %"PRIu64, offset);
1446
1447
556k
        uint64_t roffset = offset;
1448
556k
        if (offset)
1449
335k
            StreamingBufferGetDataAtOffset(&stream->sb, &mydata, &mydata_len, offset);
1450
221k
        else {
1451
221k
            StreamingBufferGetData(&stream->sb, &mydata, &mydata_len, &roffset);
1452
221k
        }
1453
1454
556k
        *data = mydata;
1455
556k
        *data_len = mydata_len;
1456
556k
        *data_offset = roffset;
1457
2.35M
    } else {
1458
2.35M
        SCLogDebug("multiblob %s. Want offset %"PRIu64,
1459
2.35M
                *iter == NULL ? "starting" : "continuing", offset);
1460
2.35M
        if (*iter == NULL) {
1461
2.23M
            StreamingBufferBlock key = { .offset = offset, .len = 0 };
1462
2.23M
            *iter = SBB_RB_FIND_INCLUSIVE((struct SBB *)&stream->sb.sbb_tree, &key);
1463
2.23M
            SCLogDebug("*iter %p", *iter);
1464
2.23M
        }
1465
2.35M
        if (*iter == NULL) {
1466
519
            SCLogDebug("no data");
1467
519
            *data = NULL;
1468
519
            *data_len = 0;
1469
519
            *data_offset = 0;
1470
519
            return 0;
1471
519
        }
1472
2.35M
        SCLogDebug("getting multiple blobs. Iter %p, %"PRIu64"/%u", *iter, (*iter)->offset, (*iter)->len);
1473
1474
2.35M
        StreamingBufferSBBGetData(&stream->sb, (*iter), &mydata, &mydata_len);
1475
2.35M
        SCLogDebug("mydata %p", mydata);
1476
1477
2.35M
        if ((*iter)->offset < offset) {
1478
2.08M
            uint64_t delta = offset - (*iter)->offset;
1479
2.08M
            if (delta < mydata_len) {
1480
2.08M
                *data = mydata + delta;
1481
2.08M
                *data_len = mydata_len - delta;
1482
2.08M
                *data_offset = offset;
1483
2.08M
            } 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
2.08M
        } else {
1491
265k
            *data = mydata;
1492
265k
            *data_len = mydata_len;
1493
265k
            *data_offset = (*iter)->offset;
1494
265k
        }
1495
1496
2.35M
        *iter = SBB_RB_NEXT(*iter);
1497
2.35M
        SCLogDebug("*iter %p", *iter);
1498
2.35M
    }
1499
2.90M
    return 0;
1500
2.90M
}
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
5.75M
{
1511
5.75M
    TcpStream *stream;
1512
5.75M
    if (PKT_IS_TOSERVER(p)) {
1513
3.05M
        stream = &ssn->client;
1514
3.05M
    } else {
1515
2.69M
        stream = &ssn->server;
1516
2.69M
    }
1517
1518
5.75M
    if (RB_EMPTY(&stream->seg_tree)) {
1519
1.07M
        return false;
1520
1.07M
    }
1521
1522
4.68M
    if (stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY|
1523
4.68M
                         STREAMTCP_STREAM_FLAG_DISABLE_RAW))
1524
3.60M
        return false;
1525
1526
1.07M
    if (StreamTcpInlineMode() == FALSE) {
1527
1.07M
        const uint64_t segs_re_abs =
1528
1.07M
                STREAM_BASE_OFFSET(stream) + stream->segs_right_edge - stream->base_seq;
1529
1.07M
        if (STREAM_RAW_PROGRESS(stream) == segs_re_abs) {
1530
36.2k
            return false;
1531
36.2k
        }
1532
1.03M
        if (StreamTcpReassembleRawCheckLimit(ssn, stream, p) == 1) {
1533
112k
            return true;
1534
112k
        }
1535
1.03M
    } else {
1536
0
        if (p->payload_len > 0 && (p->flags & PKT_STREAM_ADD)) {
1537
0
            return true;
1538
0
        }
1539
0
    }
1540
925k
    return false;
1541
1.07M
}
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
112k
{
1557
112k
    TcpStream *stream;
1558
112k
    if (PKT_IS_TOSERVER(p)) {
1559
63.9k
        stream = &ssn->client;
1560
63.9k
    } else {
1561
48.9k
        stream = &ssn->server;
1562
48.9k
    }
1563
1564
112k
    if (progress > STREAM_RAW_PROGRESS(stream)) {
1565
48.6k
        uint32_t slide = progress - STREAM_RAW_PROGRESS(stream);
1566
48.6k
        stream->raw_progress_rel += slide;
1567
48.6k
        stream->flags &= ~STREAMTCP_STREAM_FLAG_TRIGGER_RAW;
1568
1569
64.2k
    } else if (progress == 0) {
1570
33.3k
        uint64_t target;
1571
33.3k
        if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) == 0) {
1572
29.1k
            target = STREAM_APP_PROGRESS(stream);
1573
29.1k
        } else {
1574
4.21k
            target = GetAbsLastAck(stream);
1575
4.21k
        }
1576
33.3k
        if (target > STREAM_RAW_PROGRESS(stream)) {
1577
7.98k
            uint32_t slide = target - STREAM_RAW_PROGRESS(stream);
1578
7.98k
            stream->raw_progress_rel += slide;
1579
7.98k
        }
1580
33.3k
        stream->flags &= ~STREAMTCP_STREAM_FLAG_TRIGGER_RAW;
1581
1582
33.3k
    } else {
1583
30.9k
        SCLogDebug("p->pcap_cnt %"PRIu64": progress %"PRIu64" app %"PRIu64" raw %"PRIu64" tcp win %"PRIu32,
1584
30.9k
                p->pcap_cnt, progress, STREAM_APP_PROGRESS(stream),
1585
30.9k
                STREAM_RAW_PROGRESS(stream), stream->window);
1586
30.9k
    }
1587
1588
    /* if we were told to accept no more raw data, we can mark raw as
1589
     * disabled now. */
1590
112k
    if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) {
1591
866
        stream->flags |= STREAMTCP_STREAM_FLAG_DISABLE_RAW;
1592
866
        SCLogDebug("ssn %p: STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED set, "
1593
866
            "now that detect ran also set STREAMTCP_STREAM_FLAG_DISABLE_RAW", ssn);
1594
866
    }
1595
1596
112k
    SCLogDebug("stream raw progress now %"PRIu64, STREAM_RAW_PROGRESS(stream));
1597
112k
}
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
2.79M
{
1807
2.79M
    SCEnter();
1808
2.79M
    int r = 0;
1809
1810
2.79M
    StreamingBufferBlock *iter = NULL;
1811
2.79M
    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
2.90M
    while (1) {
1816
2.90M
        const uint8_t *mydata;
1817
2.90M
        uint32_t mydata_len;
1818
2.90M
        uint64_t mydata_offset = 0;
1819
1820
2.90M
        GetRawBuffer(stream, &mydata, &mydata_len, &iter, progress, &mydata_offset);
1821
2.90M
        if (mydata_len == 0) {
1822
2.08k
            SCLogDebug("no data");
1823
2.08k
            break;
1824
2.08k
        }
1825
        //PrintRawDataFp(stdout, mydata, mydata_len);
1826
1827
2.90M
        SCLogDebug("raw progress %"PRIu64, progress);
1828
2.90M
        SCLogDebug("stream %p data in buffer %p of len %u and offset %"PRIu64,
1829
2.90M
                stream, &stream->sb, mydata_len, progress);
1830
1831
2.90M
        if (eof) {
1832
            // inspect all remaining data, ack'd or not
1833
2.85M
        } else {
1834
2.85M
            if (re < progress) {
1835
5
                SCLogDebug("nothing to do");
1836
5
                goto end;
1837
5
            }
1838
1839
2.85M
            SCLogDebug("re %" PRIu64 ", raw_progress %" PRIu64, re, progress);
1840
2.85M
            SCLogDebug("raw_progress + mydata_len %" PRIu64 ", re %" PRIu64, progress + mydata_len,
1841
2.85M
                    re);
1842
1843
            /* see if the buffer contains unack'd data as well */
1844
2.85M
            if (progress + mydata_len > re) {
1845
2.52M
                uint32_t check = mydata_len;
1846
2.52M
                mydata_len = re - progress;
1847
2.52M
                BUG_ON(check < mydata_len);
1848
2.52M
                SCLogDebug("data len adjusted to %u to make sure only ACK'd "
1849
2.52M
                        "data is considered", mydata_len);
1850
2.52M
            }
1851
2.85M
        }
1852
2.90M
        if (mydata_len == 0)
1853
87.5k
            break;
1854
1855
2.81M
        SCLogDebug("data %p len %u", mydata, mydata_len);
1856
1857
        /* we have data. */
1858
2.81M
        r = Callback(cb_data, mydata, mydata_len, mydata_offset);
1859
2.81M
        BUG_ON(r < 0);
1860
1861
2.81M
        if (mydata_offset == progress) {
1862
2.62M
            SCLogDebug("progress %"PRIu64" increasing with data len %u to %"PRIu64,
1863
2.62M
                    progress, mydata_len, progress_in + mydata_len);
1864
1865
2.62M
            progress += mydata_len;
1866
2.62M
            SCLogDebug("raw progress now %"PRIu64, progress);
1867
1868
        /* data is beyond the progress we'd like, and before last ack. Gap. */
1869
2.62M
        } else if (mydata_offset > progress && mydata_offset < re) {
1870
126k
            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
126k
            SCLogDebug("re %" PRIu64, re);
1872
126k
            progress = mydata_offset;
1873
126k
            SCLogDebug("raw progress now %"PRIu64, progress);
1874
1875
126k
        } else {
1876
64.7k
            SCLogDebug("not increasing progress, data gap => mydata_offset "
1877
64.7k
                       "%"PRIu64" != progress %"PRIu64, mydata_offset, progress);
1878
64.7k
        }
1879
1880
2.81M
        if (iter == NULL || r == 1)
1881
2.70M
            break;
1882
2.81M
    }
1883
2.79M
end:
1884
2.79M
    *progress_out = progress;
1885
2.79M
    return r;
1886
2.79M
}
1887
1888
int StreamReassembleForFrame(TcpSession *ssn, TcpStream *stream, StreamReassembleRawFunc Callback,
1889
        void *cb_data, const uint64_t offset, const bool eof)
1890
2.12M
{
1891
    /* take app progress as the right edge of used data. */
1892
2.12M
    const uint64_t app_progress = STREAM_APP_PROGRESS(stream);
1893
2.12M
    SCLogDebug("app_progress %" PRIu64, app_progress);
1894
1895
2.12M
    uint64_t unused = 0;
1896
2.12M
    return StreamReassembleRawDo(
1897
2.12M
            ssn, stream, Callback, cb_data, offset, app_progress, &unused, eof, false);
1898
2.12M
}
1899
1900
int StreamReassembleRaw(TcpSession *ssn, const Packet *p,
1901
                        StreamReassembleRawFunc Callback, void *cb_data,
1902
                        uint64_t *progress_out, bool respect_inspect_depth)
1903
315k
{
1904
    /* handle inline separately as the logic is very different */
1905
315k
    if (StreamTcpInlineMode() == TRUE) {
1906
0
        return StreamReassembleRawInline(ssn, p, Callback, cb_data, progress_out);
1907
0
    }
1908
1909
315k
    TcpStream *stream;
1910
315k
    if (PKT_IS_TOSERVER(p)) {
1911
157k
        stream = &ssn->client;
1912
158k
    } else {
1913
158k
        stream = &ssn->server;
1914
158k
    }
1915
1916
315k
    if ((stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY|STREAMTCP_STREAM_FLAG_DISABLE_RAW)) ||
1917
315k
        StreamTcpReassembleRawCheckLimit(ssn, stream, p) == 0)
1918
112k
    {
1919
112k
        *progress_out = STREAM_RAW_PROGRESS(stream);
1920
112k
        return 0;
1921
112k
    }
1922
1923
203k
    uint64_t progress = STREAM_RAW_PROGRESS(stream);
1924
    /* if the app layer triggered a flush, and we're supposed to
1925
     * use a minimal inspect depth, we actually take the app progress
1926
     * as that is the right edge of the data. Then we take the window
1927
     * of 'min_inspect_depth' before that. */
1928
1929
203k
    SCLogDebug("respect_inspect_depth %s STREAMTCP_STREAM_FLAG_TRIGGER_RAW %s "
1930
203k
               "stream->min_inspect_depth %u",
1931
203k
            respect_inspect_depth ? "true" : "false",
1932
203k
            (stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW) ? "true" : "false",
1933
203k
            stream->min_inspect_depth);
1934
1935
203k
    if (respect_inspect_depth && (stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW) &&
1936
203k
            stream->min_inspect_depth) {
1937
25
        progress = STREAM_APP_PROGRESS(stream);
1938
25
        if (stream->min_inspect_depth >= progress) {
1939
25
            progress = 0;
1940
25
        } else {
1941
0
            progress -= stream->min_inspect_depth;
1942
0
        }
1943
1944
25
        SCLogDebug("stream app %" PRIu64 ", raw %" PRIu64, STREAM_APP_PROGRESS(stream),
1945
25
                STREAM_RAW_PROGRESS(stream));
1946
1947
25
        progress = MIN(progress, STREAM_RAW_PROGRESS(stream));
1948
25
        SCLogDebug("applied min inspect depth due to STREAMTCP_STREAM_FLAG_TRIGGER_RAW: progress "
1949
25
                   "%" PRIu64,
1950
25
                progress);
1951
25
    }
1952
1953
203k
    SCLogDebug("progress %" PRIu64 ", min inspect depth %u %s", progress, stream->min_inspect_depth,
1954
203k
            stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW ? "STREAMTCP_STREAM_FLAG_TRIGGER_RAW"
1955
203k
                                                              : "(no trigger)");
1956
1957
    /* absolute right edge of ack'd data */
1958
203k
    const uint64_t last_ack_abs = GetAbsLastAck(stream);
1959
203k
    SCLogDebug("last_ack_abs %" PRIu64, last_ack_abs);
1960
1961
203k
    return StreamReassembleRawDo(ssn, stream, Callback, cb_data, progress, last_ack_abs,
1962
203k
            progress_out, (p->flags & PKT_PSEUDO_STREAM_END), respect_inspect_depth);
1963
315k
}
1964
1965
int StreamReassembleLog(const TcpSession *ssn, const TcpStream *stream,
1966
        StreamReassembleRawFunc Callback, void *cb_data, const uint64_t progress_in,
1967
        uint64_t *progress_out, const bool eof)
1968
270k
{
1969
270k
    if (stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY))
1970
1
        return 0;
1971
1972
    /* absolute right edge of ack'd data */
1973
270k
    const uint64_t last_ack_abs = GetAbsLastAck(stream);
1974
270k
    SCLogDebug("last_ack_abs %" PRIu64, last_ack_abs);
1975
1976
270k
    return StreamReassembleRawDo(
1977
270k
            ssn, stream, Callback, cb_data, progress_in, last_ack_abs, progress_out, eof, false);
1978
270k
}
1979
1980
/** \internal
1981
 *  \brief update app layer based on received ACK
1982
 *
1983
 *  \retval r 0 on success, -1 on error
1984
 */
1985
static int StreamTcpReassembleHandleSegmentUpdateACK (ThreadVars *tv,
1986
        TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p)
1987
10.7M
{
1988
10.7M
    SCEnter();
1989
1990
10.7M
    if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p, UPDATE_DIR_OPPOSING) < 0)
1991
0
        SCReturnInt(-1);
1992
1993
10.7M
    SCReturnInt(0);
1994
10.7M
}
1995
1996
int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
1997
        TcpSession *ssn, TcpStream *stream, Packet *p)
1998
5.14M
{
1999
5.14M
    SCEnter();
2000
2001
5.14M
    DEBUG_VALIDATE_BUG_ON(p->tcph == NULL);
2002
2003
5.14M
    SCLogDebug("ssn %p, stream %p, p %p, p->payload_len %"PRIu16"",
2004
5.14M
                ssn, stream, p, p->payload_len);
2005
2006
    /* default IDS: update opposing side (triggered by ACK) */
2007
5.14M
    enum StreamUpdateDir dir = UPDATE_DIR_OPPOSING;
2008
    /* inline and stream end and flow timeout packets trigger same dir handling */
2009
5.14M
    if (StreamTcpInlineMode()) {
2010
0
        dir = UPDATE_DIR_PACKET;
2011
5.14M
    } else if (p->flags & PKT_PSEUDO_STREAM_END) {
2012
128k
        dir = UPDATE_DIR_PACKET;
2013
5.01M
    } else if (p->tcph->th_flags & TH_RST) { // accepted rst
2014
37.4k
        dir = UPDATE_DIR_PACKET;
2015
4.98M
    } else if ((p->tcph->th_flags & TH_FIN) && ssn->state > TCP_TIME_WAIT) {
2016
38.7k
        if (p->tcph->th_flags & TH_ACK) {
2017
12.6k
            dir = UPDATE_DIR_BOTH;
2018
26.1k
        } else {
2019
26.1k
            dir = UPDATE_DIR_PACKET;
2020
26.1k
        }
2021
4.94M
    } else if (ssn->state == TCP_CLOSED) {
2022
998
        dir = UPDATE_DIR_BOTH;
2023
998
    }
2024
2025
    /* handle ack received */
2026
5.14M
    if ((dir == UPDATE_DIR_OPPOSING || dir == UPDATE_DIR_BOTH)) {
2027
        /* we need to update the opposing stream in
2028
         * StreamTcpReassembleHandleSegmentUpdateACK */
2029
4.95M
        TcpStream *opposing_stream = NULL;
2030
4.95M
        if (stream == &ssn->client) {
2031
2.68M
            opposing_stream = &ssn->server;
2032
2.68M
        } else {
2033
2.26M
            opposing_stream = &ssn->client;
2034
2.26M
        }
2035
2036
4.95M
        const bool reversed_before_ack_handling = (p->flow->flags & FLOW_DIR_REVERSED) != 0;
2037
2038
4.95M
        if (StreamTcpReassembleHandleSegmentUpdateACK(tv, ra_ctx, ssn, opposing_stream, p) != 0) {
2039
0
            SCLogDebug("StreamTcpReassembleHandleSegmentUpdateACK error");
2040
0
            SCReturnInt(-1);
2041
0
        }
2042
2043
        /* StreamTcpReassembleHandleSegmentUpdateACK
2044
         * may swap content of ssn->server and ssn->client structures.
2045
         * We have to continue with initial content of the stream in such case */
2046
4.95M
        const bool reversed_after_ack_handling = (p->flow->flags & FLOW_DIR_REVERSED) != 0;
2047
4.95M
        if (reversed_before_ack_handling != reversed_after_ack_handling) {
2048
8.83k
            SCLogDebug("TCP streams were swapped");
2049
8.83k
            stream = opposing_stream;
2050
8.83k
        }
2051
4.95M
    }
2052
    /* if this segment contains data, insert it */
2053
5.14M
    if (p->payload_len > 0 && !(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) &&
2054
5.14M
            (p->tcph->th_flags & TH_RST) == 0) {
2055
3.57M
        SCLogDebug("calling StreamTcpReassembleHandleSegmentHandleData");
2056
2057
3.57M
        if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) != 0) {
2058
0
            SCLogDebug("StreamTcpReassembleHandleSegmentHandleData error");
2059
            /* failure can only be because of memcap hit, so see if this should lead to a drop */
2060
0
            ExceptionPolicyApply(
2061
0
                    p, stream_config.reassembly_memcap_policy, PKT_DROP_REASON_STREAM_REASSEMBLY);
2062
0
            SCReturnInt(-1);
2063
0
        }
2064
2065
3.57M
        SCLogDebug("packet %"PRIu64" set PKT_STREAM_ADD", p->pcap_cnt);
2066
3.57M
        p->flags |= PKT_STREAM_ADD;
2067
3.57M
    } else {
2068
1.56M
        SCLogDebug("ssn %p / stream %p: not calling StreamTcpReassembleHandleSegmentHandleData:"
2069
1.56M
                   " p->payload_len %u, STREAMTCP_STREAM_FLAG_NOREASSEMBLY %s",
2070
1.56M
                ssn, stream, p->payload_len,
2071
1.56M
                (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ? "true" : "false");
2072
1.56M
    }
2073
2074
    /* if the STREAMTCP_STREAM_FLAG_DEPTH_REACHED is set, but not the
2075
     * STREAMTCP_STREAM_FLAG_NOREASSEMBLY flag, it means the DEPTH flag
2076
     * was *just* set. In this case we trigger the AppLayer Truncate
2077
     * logic, to inform the applayer no more data in this direction is
2078
     * to be expected. */
2079
5.14M
    if ((stream->flags &
2080
5.14M
                (STREAMTCP_STREAM_FLAG_DEPTH_REACHED|STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) ==
2081
5.14M
            STREAMTCP_STREAM_FLAG_DEPTH_REACHED)
2082
0
    {
2083
0
        SCLogDebug("STREAMTCP_STREAM_FLAG_DEPTH_REACHED, truncate applayer");
2084
0
        if (dir != UPDATE_DIR_PACKET) {
2085
0
            SCLogDebug("override: direction now UPDATE_DIR_PACKET so we "
2086
0
                    "can trigger Truncate");
2087
0
            dir = UPDATE_DIR_PACKET;
2088
0
        }
2089
0
    }
2090
2091
    /* in stream inline mode even if we have no data we call the reassembly
2092
     * functions to handle EOF */
2093
5.14M
    if (dir == UPDATE_DIR_PACKET || dir == UPDATE_DIR_BOTH) {
2094
205k
        SCLogDebug("inline (%s) or PKT_PSEUDO_STREAM_END (%s)",
2095
205k
                StreamTcpInlineMode()?"true":"false",
2096
205k
                (p->flags & PKT_PSEUDO_STREAM_END) ?"true":"false");
2097
205k
        if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p, dir) < 0) {
2098
0
            SCReturnInt(-1);
2099
0
        }
2100
205k
    }
2101
2102
5.14M
    SCReturnInt(0);
2103
5.14M
}
2104
2105
/**
2106
 *  \brief get a segment from the pool
2107
 *
2108
 *  \retval seg Segment from the pool or NULL
2109
 */
2110
TcpSegment *StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx)
2111
8.24M
{
2112
8.24M
    TcpSegment *seg = StreamTcpThreadCacheGetSegment();
2113
8.24M
    if (seg) {
2114
4.23M
        StatsIncr(tv, ra_ctx->counter_tcp_segment_from_cache);
2115
4.23M
        memset(&seg->sbseg, 0, sizeof(seg->sbseg));
2116
4.23M
        return seg;
2117
4.23M
    }
2118
2119
4.01M
    seg = (TcpSegment *)PoolThreadGetById(
2120
4.01M
            segment_thread_pool, (uint16_t)ra_ctx->segment_thread_pool_id);
2121
4.01M
    SCLogDebug("seg we return is %p", seg);
2122
4.01M
    if (seg == NULL) {
2123
        /* Increment the counter to show that we are not able to serve the
2124
           segment request due to memcap limit */
2125
0
        StatsIncr(tv, ra_ctx->counter_tcp_segment_memcap);
2126
4.01M
    } else {
2127
4.01M
        memset(&seg->sbseg, 0, sizeof(seg->sbseg));
2128
4.01M
        StatsIncr(tv, ra_ctx->counter_tcp_segment_from_pool);
2129
4.01M
    }
2130
2131
4.01M
    return seg;
2132
8.24M
}
2133
2134
/**
2135
 *  \brief Trigger RAW stream reassembly
2136
 *
2137
 *  Used by AppLayerTriggerRawStreamReassembly to trigger RAW stream
2138
 *  reassembly from the applayer, for example upon completion of a
2139
 *  HTTP request.
2140
 *
2141
 *  It sets a flag in the stream so that the next Raw call will return
2142
 *  the data.
2143
 *
2144
 *  \param ssn TcpSession
2145
 */
2146
void StreamTcpReassembleTriggerRawReassembly(TcpSession *ssn, int direction)
2147
9.60M
{
2148
#ifdef DEBUG
2149
    BUG_ON(ssn == NULL);
2150
#endif
2151
2152
9.60M
    if (ssn != NULL) {
2153
9.60M
        if (direction == STREAM_TOSERVER) {
2154
8.12M
            ssn->client.flags |= STREAMTCP_STREAM_FLAG_TRIGGER_RAW;
2155
8.12M
        } else {
2156
1.47M
            ssn->server.flags |= STREAMTCP_STREAM_FLAG_TRIGGER_RAW;
2157
1.47M
        }
2158
2159
9.60M
        SCLogDebug("flagged ssn %p for immediate raw reassembly", ssn);
2160
9.60M
    }
2161
9.60M
}
2162
2163
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
2164
21.8M
{
2165
#ifdef DEBUG
2166
    BUG_ON(ssn == NULL);
2167
#endif
2168
2169
21.8M
    if (ssn != NULL) {
2170
21.8M
        if (direction == STREAM_TOSERVER) {
2171
20.9M
            ssn->client.min_inspect_depth = depth;
2172
20.9M
            SCLogDebug("ssn %p: set client.min_inspect_depth to %u", ssn, depth);
2173
20.9M
        } else {
2174
863k
            ssn->server.min_inspect_depth = depth;
2175
863k
            SCLogDebug("ssn %p: set server.min_inspect_depth to %u", ssn, depth);
2176
863k
        }
2177
21.8M
    }
2178
21.8M
}
2179
2180
#ifdef UNITTESTS
2181
/** unit tests and it's support functions below */
2182
2183
#define SET_ISN(stream, setseq)             \
2184
    (stream)->isn = (setseq);               \
2185
    (stream)->base_seq = (setseq) + 1
2186
2187
/** \brief  The Function to create the packet with given payload, which is used
2188
 *          to test the reassembly of the engine.
2189
 *
2190
 *  \param  payload     The variable used to store the payload contents of the
2191
 *                      current packet.
2192
 *  \param  value       The value which current payload will have for this packet
2193
 *  \param  payload_len The length of the filed payload for current packet.
2194
 *  \param  len         Length of the payload array
2195
 */
2196
2197
void StreamTcpCreateTestPacket(uint8_t *payload, uint8_t value,
2198
                               uint8_t payload_len, uint8_t len)
2199
{
2200
    uint8_t i;
2201
    for (i = 0; i < payload_len; i++)
2202
        payload[i] = value;
2203
    for (; i < len; i++)
2204
        payload = NULL;
2205
}
2206
2207
/** \brief  The Function Checks the reassembled stream contents against predefined
2208
 *          stream contents according to OS policy used.
2209
 *
2210
 *  \param  stream_policy   Predefined value of stream for different OS policies
2211
 *  \param  stream          Reassembled stream returned from the reassembly functions
2212
 */
2213
2214
int StreamTcpCheckStreamContents(uint8_t *stream_policy, uint16_t sp_size, TcpStream *stream)
2215
{
2216
    if (StreamingBufferCompareRawData(&stream->sb, stream_policy,(uint32_t)sp_size) == 0)
2217
    {
2218
        //PrintRawDataFp(stdout, stream_policy, sp_size);
2219
        return 0;
2220
    }
2221
    return 1;
2222
}
2223
2224
static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len)
2225
{
2226
    if (StreamingBufferCompareRawData(&stream->sb,
2227
                data, data_len) == 0)
2228
    {
2229
        SCReturnInt(0);
2230
    }
2231
    SCLogInfo("OK");
2232
    PrintRawDataFp(stdout, data, data_len);
2233
    return 1;
2234
}
2235
2236
#define MISSED_START(isn)                       \
2237
    TcpReassemblyThreadCtx *ra_ctx = NULL;      \
2238
    TcpSession ssn;                             \
2239
    ThreadVars tv;                              \
2240
    memset(&tv, 0, sizeof(tv));                 \
2241
                                                \
2242
    StreamTcpUTInit(&ra_ctx);                   \
2243
                                                \
2244
    StreamTcpUTSetupSession(&ssn);              \
2245
    StreamTcpUTSetupStream(&ssn.server, (isn)); \
2246
    StreamTcpUTSetupStream(&ssn.client, (isn)); \
2247
                                                \
2248
    TcpStream *stream = &ssn.client;
2249
2250
#define MISSED_END                              \
2251
    StreamTcpUTClearSession(&ssn);              \
2252
    StreamTcpUTDeinit(ra_ctx);                  \
2253
    PASS
2254
2255
#define MISSED_STEP(seq, seg, seglen, buf, buflen) \
2256
    StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen));    \
2257
    FAIL_IF(!(VALIDATE(stream, (uint8_t *)(buf), (buflen))));
2258
2259
#define MISSED_ADD_PAYLOAD(seq, seg, seglen)                                                       \
2260
    StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen));
2261
2262
int UTHCheckGapAtPosition(TcpStream *stream, int pos, uint64_t offset, uint32_t len);
2263
2264
int UTHCheckGapAtPosition(TcpStream *stream, int pos, uint64_t offset, uint32_t len)
2265
{
2266
    int cnt = 0;
2267
    uint64_t last_re = 0;
2268
    StreamingBufferBlock *sbb = NULL;
2269
    RB_FOREACH(sbb, SBB, &stream->sb.sbb_tree)
2270
    {
2271
        if (sbb->offset != last_re) {
2272
            // gap before us
2273
            if (cnt == pos && last_re == offset && len == sbb->offset - last_re) {
2274
                return 1;
2275
            }
2276
            cnt++;
2277
        }
2278
        last_re = sbb->offset + sbb->len;
2279
        cnt++;
2280
    }
2281
    return 0;
2282
}
2283
2284
int UTHCheckDataAtPosition(
2285
        TcpStream *stream, int pos, uint64_t offset, const char *data, uint32_t len);
2286
2287
int UTHCheckDataAtPosition(
2288
        TcpStream *stream, int pos, uint64_t offset, const char *data, uint32_t len)
2289
{
2290
    int cnt = 0;
2291
    uint64_t last_re = 0;
2292
    StreamingBufferBlock *sbb = NULL;
2293
    RB_FOREACH(sbb, SBB, &stream->sb.sbb_tree)
2294
    {
2295
        if (sbb->offset != last_re) {
2296
            // gap before us
2297
            cnt++;
2298
        }
2299
2300
        if (cnt == pos && sbb->offset == offset) {
2301
            const uint8_t *buf = NULL;
2302
            uint32_t buf_len = 0;
2303
            StreamingBufferSBBGetData(&stream->sb, sbb, &buf, &buf_len);
2304
2305
            if (len == buf_len) {
2306
                return (memcmp(data, buf, len) == 0);
2307
            }
2308
        }
2309
2310
        last_re = sbb->offset + sbb->len;
2311
        cnt++;
2312
    }
2313
    return 0;
2314
}
2315
2316
/**
2317
 *  \test   Test the handling of packets missed by both IDS and the end host.
2318
 *          The packet is missed in the starting of the stream.
2319
 *
2320
 *  \retval On success it returns 1 and on failure 0.
2321
 */
2322
2323
static int StreamTcpReassembleTest25 (void)
2324
{
2325
    MISSED_START(6);
2326
    MISSED_ADD_PAYLOAD(10, "BB", 2);
2327
    FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2328
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "BB", 2) == 1);
2329
    MISSED_ADD_PAYLOAD(12, "CC", 2);
2330
    FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2331
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "BBCC", 4) == 1);
2332
    MISSED_STEP(7, "AAA", 3, "AAABBCC", 7);
2333
    MISSED_END;
2334
    PASS;
2335
}
2336
2337
/**
2338
 *  \test   Test the handling of packets missed by both IDS and the end host.
2339
 *          The packet is missed in the middle of the stream.
2340
 *
2341
 *  \retval On success it returns 1 and on failure 0.
2342
 */
2343
2344
static int StreamTcpReassembleTest26 (void)
2345
{
2346
    MISSED_START(9);
2347
    MISSED_STEP(10, "AAA", 3, "AAA", 3);
2348
    MISSED_ADD_PAYLOAD(15, "CC", 2);
2349
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 0, 0, "AAA", 3) == 1);
2350
    FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 1, 3, 2) == 1);
2351
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 2, 5, "CC", 2) == 1);
2352
    MISSED_STEP(13, "BB", 2, "AAABBCC", 7);
2353
    MISSED_END;
2354
}
2355
2356
/**
2357
 *  \test   Test the handling of packets missed by both IDS and the end host.
2358
 *          The packet is missed in the end of the stream.
2359
 *
2360
 *  \retval On success it returns 1 and on failure 0.
2361
 */
2362
2363
static int StreamTcpReassembleTest27 (void)
2364
{
2365
    MISSED_START(9);
2366
    MISSED_STEP(10, "AAA", 3, "AAA", 3);
2367
    MISSED_STEP(13, "BB", 2, "AAABB", 5);
2368
    MISSED_STEP(15, "CC", 2, "AAABBCC", 7);
2369
    MISSED_END;
2370
}
2371
2372
/**
2373
 *  \test   Test the handling of packets missed by IDS, but the end host has
2374
 *          received it and send the acknowledgment of it. The packet is missed
2375
 *          in the starting of the stream.
2376
 *
2377
 *  \retval On success it returns 1 and on failure 0.
2378
 */
2379
2380
static int StreamTcpReassembleTest28 (void)
2381
{
2382
    MISSED_START(6);
2383
    MISSED_ADD_PAYLOAD(10, "AAA", 3);
2384
    FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2385
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "AAA", 3) == 1);
2386
    MISSED_ADD_PAYLOAD(13, "BB", 2);
2387
    FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2388
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "AAABB", 5) == 1);
2389
    ssn.state = TCP_TIME_WAIT;
2390
    MISSED_ADD_PAYLOAD(15, "CC", 2);
2391
    FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2392
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "AAABBCC", 7) == 1);
2393
    MISSED_END;
2394
}
2395
2396
/**
2397
 *  \test   Test the handling of packets missed by IDS, but the end host has
2398
 *          received it and send the acknowledgment of it. The packet is missed
2399
 *          in the middle of the stream.
2400
 *
2401
 *  \retval On success it returns 1 and on failure 0.
2402
 */
2403
2404
static int StreamTcpReassembleTest29 (void)
2405
{
2406
    MISSED_START(9);
2407
    MISSED_STEP(10, "AAA", 3, "AAA", 3);
2408
    ssn.state = TCP_TIME_WAIT;
2409
    MISSED_ADD_PAYLOAD(15, "CC", 2);
2410
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 0, 0, "AAA", 3) == 1);
2411
    FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 1, 3, 2) == 1);
2412
    FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 2, 5, "CC", 2) == 1);
2413
    MISSED_END;
2414
}
2415
2416
static int StreamTcpReassembleTest33(void)
2417
{
2418
    TcpSession ssn;
2419
    Packet *p = PacketGetFromAlloc();
2420
    FAIL_IF(unlikely(p == NULL));
2421
    Flow f;
2422
    TCPHdr tcph;
2423
    TcpReassemblyThreadCtx *ra_ctx = NULL;
2424
    ssn.client.os_policy = OS_POLICY_BSD;
2425
    uint8_t packet[1460] = "";
2426
2427
    StreamTcpUTInit(&ra_ctx);
2428
    StreamTcpUTSetupSession(&ssn);
2429
2430
    memset(&f, 0, sizeof (Flow));
2431
    memset(&tcph, 0, sizeof (TCPHdr));
2432
    ThreadVars tv;
2433
    memset(&tv, 0, sizeof (ThreadVars));
2434
    FLOW_INITIALIZE(&f);
2435
    f.protoctx = &ssn;
2436
    f.proto = IPPROTO_TCP;
2437
    p->src.family = AF_INET;
2438
    p->dst.family = AF_INET;
2439
    p->proto = IPPROTO_TCP;
2440
    p->flow = &f;
2441
    tcph.th_win = 5480;
2442
    tcph.th_flags = TH_PUSH | TH_ACK;
2443
    p->tcph = &tcph;
2444
    p->flowflags = FLOW_PKT_TOSERVER;
2445
    p->payload = packet;
2446
2447
    p->tcph->th_seq = htonl(10);
2448
    p->tcph->th_ack = htonl(31);
2449
    p->payload_len = 10;
2450
2451
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2452
2453
    p->tcph->th_seq = htonl(20);
2454
    p->tcph->th_ack = htonl(31);
2455
    p->payload_len = 10;
2456
2457
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2458
2459
    p->tcph->th_seq = htonl(40);
2460
    p->tcph->th_ack = htonl(31);
2461
    p->payload_len = 10;
2462
2463
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2464
2465
    p->tcph->th_seq = htonl(5);
2466
    p->tcph->th_ack = htonl(31);
2467
    p->payload_len = 30;
2468
2469
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2470
2471
    StreamTcpUTClearSession(&ssn);
2472
    StreamTcpUTDeinit(ra_ctx);
2473
    SCFree(p);
2474
    PASS;
2475
}
2476
2477
static int StreamTcpReassembleTest34(void)
2478
{
2479
    TcpSession ssn;
2480
    Packet *p = PacketGetFromAlloc();
2481
    FAIL_IF(unlikely(p == NULL));
2482
    Flow f;
2483
    TCPHdr tcph;
2484
    TcpReassemblyThreadCtx *ra_ctx = NULL;
2485
    ssn.client.os_policy = OS_POLICY_BSD;
2486
    uint8_t packet[1460] = "";
2487
2488
    StreamTcpUTInit(&ra_ctx);
2489
    StreamTcpUTSetupSession(&ssn);
2490
    memset(&f, 0, sizeof (Flow));
2491
    memset(&tcph, 0, sizeof (TCPHdr));
2492
    ThreadVars tv;
2493
    memset(&tv, 0, sizeof (ThreadVars));
2494
    FLOW_INITIALIZE(&f);
2495
    f.protoctx = &ssn;
2496
    f.proto = IPPROTO_TCP;
2497
    p->src.family = AF_INET;
2498
    p->dst.family = AF_INET;
2499
    p->proto = IPPROTO_TCP;
2500
    p->flow = &f;
2501
    tcph.th_win = 5480;
2502
    tcph.th_flags = TH_PUSH | TH_ACK;
2503
    p->tcph = &tcph;
2504
    p->flowflags = FLOW_PKT_TOSERVER;
2505
    p->payload = packet;
2506
    SET_ISN(&ssn.client, 857961230);
2507
2508
    p->tcph->th_seq = htonl(857961230);
2509
    p->tcph->th_ack = htonl(31);
2510
    p->payload_len = 304;
2511
2512
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2513
2514
    p->tcph->th_seq = htonl(857961534);
2515
    p->tcph->th_ack = htonl(31);
2516
    p->payload_len = 1460;
2517
2518
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2519
2520
    p->tcph->th_seq = htonl(857963582);
2521
    p->tcph->th_ack = htonl(31);
2522
    p->payload_len = 1460;
2523
2524
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2525
2526
    p->tcph->th_seq = htonl(857960946);
2527
    p->tcph->th_ack = htonl(31);
2528
    p->payload_len = 1460;
2529
2530
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2531
2532
    StreamTcpUTClearSession(&ssn);
2533
    StreamTcpUTDeinit(ra_ctx);
2534
    SCFree(p);
2535
    PASS;
2536
}
2537
2538
/**
2539
 *  \test   Test to make sure that we don't return the segments until the app
2540
 *          layer proto has been detected and after that remove the processed
2541
 *          segments.
2542
 *
2543
 *  \retval On success it returns 1 and on failure 0.
2544
 */
2545
2546
static int StreamTcpReassembleTest39 (void)
2547
{
2548
    Packet *p = PacketGetFromAlloc();
2549
    FAIL_IF(unlikely(p == NULL));
2550
    Flow f;
2551
    ThreadVars tv;
2552
    StreamTcpThread stt;
2553
    TCPHdr tcph;
2554
    PacketQueueNoLock pq;
2555
    memset(&pq,0,sizeof(PacketQueueNoLock));
2556
    memset (&f, 0, sizeof(Flow));
2557
    memset(&tv, 0, sizeof (ThreadVars));
2558
    memset(&stt, 0, sizeof (stt));
2559
    memset(&tcph, 0, sizeof (TCPHdr));
2560
2561
    FLOW_INITIALIZE(&f);
2562
    f.flags = FLOW_IPV4;
2563
    f.proto = IPPROTO_TCP;
2564
    p->flow = &f;
2565
    p->tcph = &tcph;
2566
2567
    StreamTcpUTInit(&stt.ra_ctx);
2568
2569
    /* handshake */
2570
    tcph.th_win = htons(5480);
2571
    tcph.th_flags = TH_SYN;
2572
    p->flowflags = FLOW_PKT_TOSERVER;
2573
    p->payload_len = 0;
2574
    p->payload = NULL;
2575
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2576
2577
    TcpSession *ssn = (TcpSession *)f.protoctx;
2578
    FAIL_IF_NULL(ssn);
2579
2580
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2581
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2582
    FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
2583
    FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
2584
    FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
2585
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2586
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2587
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2588
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2589
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2590
    FAIL_IF(!RB_EMPTY(&ssn->client.seg_tree));
2591
    FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2592
    FAIL_IF(ssn->data_first_seen_dir != 0);
2593
2594
    /* handshake */
2595
    p->tcph->th_ack = htonl(1);
2596
    p->tcph->th_flags = TH_SYN | TH_ACK;
2597
    p->flowflags = FLOW_PKT_TOCLIENT;
2598
    p->payload_len = 0;
2599
    p->payload = NULL;
2600
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2601
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2602
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2603
    FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
2604
    FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
2605
    FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
2606
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2607
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2608
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2609
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2610
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2611
    FAIL_IF(!RB_EMPTY(&ssn->client.seg_tree));
2612
    FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2613
    FAIL_IF(ssn->data_first_seen_dir != 0);
2614
2615
    /* handshake */
2616
    p->tcph->th_ack = htonl(1);
2617
    p->tcph->th_seq = htonl(1);
2618
    p->tcph->th_flags = TH_ACK;
2619
    p->flowflags = FLOW_PKT_TOSERVER;
2620
    p->payload_len = 0;
2621
    p->payload = NULL;
2622
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2623
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2624
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2625
    FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
2626
    FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
2627
    FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
2628
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2629
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2630
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2631
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2632
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2633
    FAIL_IF(!RB_EMPTY(&ssn->client.seg_tree));
2634
    FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2635
    FAIL_IF(ssn->data_first_seen_dir != 0);
2636
2637
    /* partial request */
2638
    uint8_t request1[] = { 0x47, 0x45, };
2639
    p->tcph->th_ack = htonl(1);
2640
    p->tcph->th_seq = htonl(1);
2641
    p->tcph->th_flags = TH_PUSH | TH_ACK;
2642
    p->flowflags = FLOW_PKT_TOSERVER;
2643
    p->payload_len = sizeof(request1);
2644
    p->payload = request1;
2645
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2646
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2647
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2648
    FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
2649
    FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
2650
    FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
2651
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2652
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2653
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2654
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2655
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2656
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2657
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2658
    FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2659
    FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER);
2660
2661
    /* response ack against partial request */
2662
    p->tcph->th_ack = htonl(3);
2663
    p->tcph->th_seq = htonl(1);
2664
    p->tcph->th_flags = TH_ACK;
2665
    p->flowflags = FLOW_PKT_TOCLIENT;
2666
    p->payload_len = 0;
2667
    p->payload = NULL;
2668
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2669
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2670
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2671
    FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
2672
    FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
2673
    FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
2674
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2675
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2676
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2677
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2678
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2679
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2680
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2681
    FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2682
    FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER);
2683
2684
    /* complete partial request */
2685
    uint8_t request2[] = {
2686
        0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64,
2687
        0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20,
2688
        0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30,
2689
        0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20,
2690
        0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73,
2691
        0x74, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d,
2692
        0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x41,
2693
        0x70, 0x61, 0x63, 0x68, 0x65, 0x42, 0x65, 0x6e,
2694
        0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a,
2695
        0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20,
2696
        0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a };
2697
    p->tcph->th_ack = htonl(1);
2698
    p->tcph->th_seq = htonl(3);
2699
    p->tcph->th_flags = TH_PUSH | TH_ACK;
2700
    p->flowflags = FLOW_PKT_TOSERVER;
2701
    p->payload_len = sizeof(request2);
2702
    p->payload = request2;
2703
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2704
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2705
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2706
    FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
2707
    FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
2708
    FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
2709
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2710
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2711
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2712
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2713
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2714
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2715
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2716
    FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2717
    FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2718
    FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER);
2719
2720
    /* response - request ack */
2721
    uint8_t response[] = {
2722
        0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31,
2723
        0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d,
2724
        0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x46,
2725
        0x72, 0x69, 0x2c, 0x20, 0x32, 0x33, 0x20, 0x53,
2726
        0x65, 0x70, 0x20, 0x32, 0x30, 0x31, 0x31, 0x20,
2727
        0x30, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x39,
2728
        0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65,
2729
        0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x41, 0x70,
2730
        0x61, 0x63, 0x68, 0x65, 0x2f, 0x32, 0x2e, 0x32,
2731
        0x2e, 0x31, 0x35, 0x20, 0x28, 0x55, 0x6e, 0x69,
2732
        0x78, 0x29, 0x20, 0x44, 0x41, 0x56, 0x2f, 0x32,
2733
        0x0d, 0x0a, 0x4c, 0x61, 0x73, 0x74, 0x2d, 0x4d,
2734
        0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x3a,
2735
        0x20, 0x54, 0x68, 0x75, 0x2c, 0x20, 0x30, 0x34,
2736
        0x20, 0x4e, 0x6f, 0x76, 0x20, 0x32, 0x30, 0x31,
2737
        0x30, 0x20, 0x31, 0x35, 0x3a, 0x30, 0x34, 0x3a,
2738
        0x34, 0x36, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a,
2739
        0x45, 0x54, 0x61, 0x67, 0x3a, 0x20, 0x22, 0x61,
2740
        0x62, 0x38, 0x39, 0x36, 0x35, 0x2d, 0x32, 0x63,
2741
        0x2d, 0x34, 0x39, 0x34, 0x33, 0x62, 0x37, 0x61,
2742
        0x37, 0x66, 0x37, 0x66, 0x38, 0x30, 0x22, 0x0d,
2743
        0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d,
2744
        0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x3a, 0x20,
2745
        0x62, 0x79, 0x74, 0x65, 0x73, 0x0d, 0x0a, 0x43,
2746
        0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c,
2747
        0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x34,
2748
        0x34, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
2749
        0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63,
2750
        0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, 0x43, 0x6f,
2751
        0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79,
2752
        0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74,
2753
        0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x58,
2754
        0x2d, 0x50, 0x61, 0x64, 0x3a, 0x20, 0x61, 0x76,
2755
        0x6f, 0x69, 0x64, 0x20, 0x62, 0x72, 0x6f, 0x77,
2756
        0x73, 0x65, 0x72, 0x20, 0x62, 0x75, 0x67, 0x0d,
2757
        0x0a, 0x0d, 0x0a, 0x3c, 0x68, 0x74, 0x6d, 0x6c,
2758
        0x3e, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c,
2759
        0x68, 0x31, 0x3e, 0x49, 0x74, 0x20, 0x77, 0x6f,
2760
        0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31,
2761
        0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e,
2762
        0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e };
2763
    p->tcph->th_ack = htonl(88);
2764
    p->tcph->th_seq = htonl(1);
2765
    p->tcph->th_flags = TH_PUSH | TH_ACK;
2766
    p->flowflags = FLOW_PKT_TOCLIENT;
2767
    p->payload_len = sizeof(response);
2768
    p->payload = response;
2769
2770
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2771
    FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2772
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2773
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2774
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2775
    FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
2776
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2777
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2778
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2779
    FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2780
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2781
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2782
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2783
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2784
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2785
    FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2786
2787
    /* response ack from request */
2788
    p->tcph->th_ack = htonl(328);
2789
    p->tcph->th_seq = htonl(88);
2790
    p->tcph->th_flags = TH_ACK;
2791
    p->flowflags = FLOW_PKT_TOSERVER;
2792
    p->payload_len = 0;
2793
    p->payload = NULL;
2794
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2795
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2796
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2797
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2798
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2799
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2800
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2801
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2802
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2803
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2804
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2805
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2806
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2807
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2808
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2809
    FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2810
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2811
2812
    /* response - acking */
2813
    p->tcph->th_ack = htonl(88);
2814
    p->tcph->th_seq = htonl(328);
2815
    p->tcph->th_flags = TH_PUSH | TH_ACK;
2816
    p->flowflags = FLOW_PKT_TOCLIENT;
2817
    p->payload_len = 0;
2818
    p->payload = NULL;
2819
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2820
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2821
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2822
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2823
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2824
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2825
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2826
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2827
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2828
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2829
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2830
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2831
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2832
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2833
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2834
    FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2835
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2836
2837
    /* response ack from request */
2838
    p->tcph->th_ack = htonl(328);
2839
    p->tcph->th_seq = htonl(88);
2840
    p->tcph->th_flags = TH_ACK;
2841
    p->flowflags = FLOW_PKT_TOSERVER;
2842
    p->payload_len = 0;
2843
    p->payload = NULL;
2844
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2845
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2846
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2847
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2848
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2849
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2850
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2851
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2852
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2853
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2854
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2855
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2856
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2857
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2858
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2859
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2860
2861
    /* response - acking the request again*/
2862
    p->tcph->th_ack = htonl(88);
2863
    p->tcph->th_seq = htonl(328);
2864
    p->tcph->th_flags = TH_PUSH | TH_ACK;
2865
    p->flowflags = FLOW_PKT_TOCLIENT;
2866
    p->payload_len = 0;
2867
    p->payload = NULL;
2868
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2869
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2870
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2871
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2872
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2873
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2874
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2875
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2876
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2877
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2878
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2879
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2880
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2881
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2882
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2883
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2884
2885
    /*** New Request ***/
2886
2887
    /* partial request */
2888
    p->tcph->th_ack = htonl(328);
2889
    p->tcph->th_seq = htonl(88);
2890
    p->tcph->th_flags = TH_PUSH | TH_ACK;
2891
    p->flowflags = FLOW_PKT_TOSERVER;
2892
    p->payload_len = sizeof(request1);
2893
    p->payload = request1;
2894
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2895
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2896
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2897
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2898
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2899
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2900
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2901
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2902
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2903
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2904
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2905
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2906
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2907
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2908
    FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2909
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2910
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2911
2912
    /* response ack against partial request */
2913
    p->tcph->th_ack = htonl(90);
2914
    p->tcph->th_seq = htonl(328);
2915
    p->tcph->th_flags = TH_ACK;
2916
    p->flowflags = FLOW_PKT_TOCLIENT;
2917
    p->payload_len = 0;
2918
    p->payload = NULL;
2919
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2920
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2921
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2922
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2923
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2924
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2925
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2926
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2927
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2928
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2929
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2930
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2931
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2932
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2933
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2934
    FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2935
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2936
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2937
2938
    /* complete request */
2939
    p->tcph->th_ack = htonl(328);
2940
    p->tcph->th_seq = htonl(90);
2941
    p->tcph->th_flags = TH_PUSH | TH_ACK;
2942
    p->flowflags = FLOW_PKT_TOSERVER;
2943
    p->payload_len = sizeof(request2);
2944
    p->payload = request2;
2945
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2946
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2947
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2948
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2949
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2950
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2951
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2952
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2953
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2954
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2955
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2956
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2957
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2958
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2959
    FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2960
    FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)))));
2961
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2962
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2963
2964
    /* response ack against second partial request */
2965
    p->tcph->th_ack = htonl(175);
2966
    p->tcph->th_seq = htonl(328);
2967
    p->tcph->th_flags = TH_ACK;
2968
    p->flowflags = FLOW_PKT_TOCLIENT;
2969
    p->payload_len = 0;
2970
    p->payload = NULL;
2971
2972
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2973
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
2974
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
2975
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
2976
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
2977
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
2978
    FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
2979
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2980
    FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2981
    FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2982
    FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2983
    FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
2984
    FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2985
    FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2986
    FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2987
    FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)))));
2988
    FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2989
    FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2990
2991
    /* response acking a request */
2992
    p->tcph->th_ack = htonl(175);
2993
    p->tcph->th_seq = htonl(328);
2994
    p->tcph->th_flags = TH_ACK;
2995
    p->flowflags = FLOW_PKT_TOCLIENT;
2996
    p->payload_len = 0;
2997
    p->payload = NULL;
2998
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2999
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
3000
    FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
3001
    FAIL_IF(f.alproto != ALPROTO_HTTP1);
3002
    FAIL_IF(f.alproto_ts != ALPROTO_HTTP1);
3003
    FAIL_IF(f.alproto_tc != ALPROTO_HTTP1);
3004
3005
    StreamTcpPruneSession(&f, STREAM_TOSERVER);
3006
    StreamTcpPruneSession(&f, STREAM_TOCLIENT);
3007
3008
    /* request acking a response */
3009
    p->tcph->th_ack = htonl(328);
3010
    p->tcph->th_seq = htonl(175);
3011
    p->tcph->th_flags = TH_ACK;
3012
    p->flowflags = FLOW_PKT_TOSERVER;
3013
    p->payload_len = 0;
3014
    p->payload = NULL;
3015
    FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
3016
3017
    StreamTcpSessionClear(ssn);
3018
    StreamTcpUTDeinit(stt.ra_ctx);
3019
    SCFree(p);
3020
    PASS;
3021
}
3022
3023
/**
3024
 *  \test   Test to make sure that we sent all the segments from the initial
3025
 *          segments to app layer until we have detected the app layer proto.
3026
 *
3027
 *  \retval On success it returns 1 and on failure 0.
3028
 */
3029
3030
static int StreamTcpReassembleTest40 (void)
3031
{
3032
    Packet *p = PacketGetFromAlloc();
3033
    FAIL_IF_NULL(p);
3034
    Flow *f = NULL;
3035
    TCPHdr tcph;
3036
    TcpSession ssn;
3037
    memset(&tcph, 0, sizeof (TCPHdr));
3038
    ThreadVars tv;
3039
    memset(&tv, 0, sizeof (ThreadVars));
3040
3041
    StreamTcpInitConfig(true);
3042
    StreamTcpUTSetupSession(&ssn);
3043
3044
    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(&tv);
3045
    FAIL_IF_NULL(ra_ctx);
3046
3047
    uint8_t httpbuf1[] = "P";
3048
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3049
    uint8_t httpbuf3[] = "O";
3050
    uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
3051
    uint8_t httpbuf4[] = "S";
3052
    uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
3053
    uint8_t httpbuf5[] = "T \r\n";
3054
    uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
3055
3056
    uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
3057
    uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3058
3059
    SET_ISN(&ssn.server, 9);
3060
    ssn.server.last_ack = 10;
3061
    SET_ISN(&ssn.client, 9);
3062
    ssn.client.isn = 9;
3063
3064
    f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
3065
    FAIL_IF_NULL(f);
3066
    f->protoctx = &ssn;
3067
    f->proto = IPPROTO_TCP;
3068
    p->flow = f;
3069
3070
    tcph.th_win = htons(5480);
3071
    tcph.th_seq = htonl(10);
3072
    tcph.th_ack = htonl(10);
3073
    tcph.th_flags = TH_ACK|TH_PUSH;
3074
    p->tcph = &tcph;
3075
    p->flowflags = FLOW_PKT_TOSERVER;
3076
    p->payload = httpbuf1;
3077
    p->payload_len = httplen1;
3078
    ssn.state = TCP_ESTABLISHED;
3079
    TcpStream *s = &ssn.client;
3080
    SCLogDebug("1 -- start");
3081
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3082
3083
    p->flowflags = FLOW_PKT_TOCLIENT;
3084
    p->payload = httpbuf2;
3085
    p->payload_len = httplen2;
3086
    tcph.th_seq = htonl(10);
3087
    tcph.th_ack = htonl(11);
3088
    s = &ssn.server;
3089
    ssn.server.last_ack = 11;
3090
    SCLogDebug("2 -- start");
3091
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3092
3093
    p->flowflags = FLOW_PKT_TOSERVER;
3094
    p->payload = httpbuf3;
3095
    p->payload_len = httplen3;
3096
    tcph.th_seq = htonl(11);
3097
    tcph.th_ack = htonl(55);
3098
    s = &ssn.client;
3099
    ssn.client.last_ack = 55;
3100
    SCLogDebug("3 -- start");
3101
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3102
3103
    p->flowflags = FLOW_PKT_TOCLIENT;
3104
    p->payload = httpbuf2;
3105
    p->payload_len = httplen2;
3106
    tcph.th_seq = htonl(55);
3107
    tcph.th_ack = htonl(12);
3108
    s = &ssn.server;
3109
    ssn.server.last_ack = 12;
3110
    SCLogDebug("4 -- start");
3111
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3112
3113
    /* check is have the segment in the list and flagged or not */
3114
    TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3115
    FAIL_IF_NULL(seg);
3116
    FAIL_IF(SEGMENT_BEFORE_OFFSET(&ssn.client, seg, STREAM_APP_PROGRESS(&ssn.client)));
3117
3118
    p->flowflags = FLOW_PKT_TOSERVER;
3119
    p->payload = httpbuf4;
3120
    p->payload_len = httplen4;
3121
    tcph.th_seq = htonl(12);
3122
    tcph.th_ack = htonl(100);
3123
    s = &ssn.client;
3124
    ssn.client.last_ack = 100;
3125
    SCLogDebug("5 -- start");
3126
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3127
3128
    p->flowflags = FLOW_PKT_TOCLIENT;
3129
    p->payload = httpbuf2;
3130
    p->payload_len = httplen2;
3131
    tcph.th_seq = htonl(100);
3132
    tcph.th_ack = htonl(13);
3133
    s = &ssn.server;
3134
    ssn.server.last_ack = 13;
3135
    SCLogDebug("6 -- start");
3136
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3137
3138
    p->flowflags = FLOW_PKT_TOSERVER;
3139
    p->payload = httpbuf5;
3140
    p->payload_len = httplen5;
3141
    tcph.th_seq = htonl(13);
3142
    tcph.th_ack = htonl(145);
3143
    s = &ssn.client;
3144
    ssn.client.last_ack = 145;
3145
    SCLogDebug("7 -- start");
3146
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3147
3148
    p->flowflags = FLOW_PKT_TOCLIENT;
3149
    p->payload = httpbuf2;
3150
    p->payload_len = httplen2;
3151
    tcph.th_seq = htonl(145);
3152
    tcph.th_ack = htonl(16);
3153
    s = &ssn.server;
3154
    ssn.server.last_ack = 16;
3155
    SCLogDebug("8 -- start");
3156
    FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3157
    FAIL_IF(f->alproto != ALPROTO_HTTP1);
3158
3159
    StreamTcpUTClearSession(&ssn);
3160
    StreamTcpReassembleFreeThreadCtx(ra_ctx);
3161
    StreamTcpFreeConfig(true);
3162
    SCFree(p);
3163
    UTHFreeFlow(f);
3164
    PASS;
3165
}
3166
3167
/** \test   Test the memcap incrementing/decrementing and memcap check */
3168
static int StreamTcpReassembleTest44(void)
3169
{
3170
    StreamTcpInitConfig(true);
3171
    uint32_t memuse = SC_ATOMIC_GET(ra_memuse);
3172
    StreamTcpReassembleIncrMemuse(500);
3173
    FAIL_IF(SC_ATOMIC_GET(ra_memuse) != (memuse+500));
3174
    StreamTcpReassembleDecrMemuse(500);
3175
    FAIL_IF(SC_ATOMIC_GET(ra_memuse) != memuse);
3176
    FAIL_IF(StreamTcpReassembleCheckMemcap(500) != 1);
3177
    FAIL_IF(StreamTcpReassembleCheckMemcap((1 + memuse + SC_ATOMIC_GET(stream_config.reassembly_memcap))) != 0);
3178
    StreamTcpFreeConfig(true);
3179
    FAIL_IF(SC_ATOMIC_GET(ra_memuse) != 0);
3180
    PASS;
3181
}
3182
3183
/**
3184
 *  \test   Test to make sure that reassembly_depth is enforced.
3185
 *
3186
 *  \retval On success it returns 1 and on failure 0.
3187
 */
3188
3189
static int StreamTcpReassembleTest45 (void)
3190
{
3191
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3192
    TcpSession ssn;
3193
    ThreadVars tv;
3194
    memset(&tv, 0, sizeof(tv));
3195
    uint8_t payload[100] = {0};
3196
    uint16_t payload_size = 100;
3197
3198
    StreamTcpUTInit(&ra_ctx);
3199
    stream_config.reassembly_depth = 100;
3200
3201
    StreamTcpUTSetupSession(&ssn);
3202
    ssn.reassembly_depth = 100;
3203
    StreamTcpUTSetupStream(&ssn.server, 100);
3204
    StreamTcpUTSetupStream(&ssn.client, 100);
3205
3206
    int r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size);
3207
    FAIL_IF(r != 0);
3208
    FAIL_IF(ssn.client.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED);
3209
3210
    r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size);
3211
    FAIL_IF(r != 0);
3212
    FAIL_IF(!(ssn.client.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED));
3213
3214
    StreamTcpUTClearStream(&ssn.server);
3215
    StreamTcpUTClearStream(&ssn.client);
3216
    StreamTcpUTClearSession(&ssn);
3217
    StreamTcpUTDeinit(ra_ctx);
3218
    PASS;
3219
}
3220
3221
/**
3222
 *  \test   Test the unlimited config value of reassembly depth.
3223
 *
3224
 *  \retval On success it returns 1 and on failure 0.
3225
 */
3226
3227
static int StreamTcpReassembleTest46 (void)
3228
{
3229
    int result = 0;
3230
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3231
    TcpSession ssn;
3232
    ThreadVars tv;
3233
    memset(&tv, 0, sizeof(tv));
3234
    uint8_t payload[100] = {0};
3235
    uint16_t payload_size = 100;
3236
3237
    StreamTcpUTInit(&ra_ctx);
3238
    stream_config.reassembly_depth = 0;
3239
3240
    StreamTcpUTSetupSession(&ssn);
3241
    StreamTcpUTSetupStream(&ssn.server, 100);
3242
    StreamTcpUTSetupStream(&ssn.client, 100);
3243
3244
    int r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size);
3245
    if (r != 0)
3246
        goto end;
3247
    if (ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
3248
        printf("STREAMTCP_STREAM_FLAG_NOREASSEMBLY set: ");
3249
        goto end;
3250
    }
3251
3252
    r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size);
3253
    if (r != 0)
3254
        goto end;
3255
    if (ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
3256
        printf("STREAMTCP_STREAM_FLAG_NOREASSEMBLY set: ");
3257
        goto end;
3258
    }
3259
3260
    result = 1;
3261
end:
3262
    StreamTcpUTClearStream(&ssn.server);
3263
    StreamTcpUTClearStream(&ssn.client);
3264
    StreamTcpUTClearSession(&ssn);
3265
    StreamTcpUTDeinit(ra_ctx);
3266
    return result;
3267
}
3268
3269
/**
3270
 *  \test   Test to make sure we detect the sequence wrap around and continue
3271
 *          stream reassembly properly.
3272
 *
3273
 *  \retval On success it returns 1 and on failure 0.
3274
 */
3275
3276
static int StreamTcpReassembleTest47 (void)
3277
{
3278
    Packet *p = PacketGetFromAlloc();
3279
    FAIL_IF(unlikely(p == NULL));
3280
    Flow *f = NULL;
3281
    TCPHdr tcph;
3282
    TcpSession ssn;
3283
    ThreadVars tv;
3284
    memset(&tcph, 0, sizeof (TCPHdr));
3285
    memset(&tv, 0, sizeof (ThreadVars));
3286
    StreamTcpInitConfig(true);
3287
    StreamTcpUTSetupSession(&ssn);
3288
    TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(&tv);
3289
3290
    uint8_t httpbuf1[] = "GET /EVILSUFF HTTP/1.1\r\n\r\n";
3291
    uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3292
3293
    SET_ISN(&ssn.server, 572799781UL);
3294
    ssn.server.last_ack = 572799782UL;
3295
3296
    SET_ISN(&ssn.client, 4294967289UL);
3297
    ssn.client.last_ack = 21;
3298
3299
    f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
3300
    FAIL_IF(f == NULL);
3301
    f->protoctx = &ssn;
3302
    f->proto = IPPROTO_TCP;
3303
    p->flow = f;
3304
3305
    tcph.th_win = htons(5480);
3306
    ssn.state = TCP_ESTABLISHED;
3307
    TcpStream *s = NULL;
3308
    uint8_t cnt = 0;
3309
3310
    for (cnt=0; cnt < httplen1; cnt++) {
3311
        tcph.th_seq = htonl(ssn.client.isn + 1 + cnt);
3312
        tcph.th_ack = htonl(572799782UL);
3313
        tcph.th_flags = TH_ACK|TH_PUSH;
3314
        p->tcph = &tcph;
3315
        p->flowflags = FLOW_PKT_TOSERVER;
3316
        p->payload = &httpbuf1[cnt];
3317
        p->payload_len = 1;
3318
        s = &ssn.client;
3319
3320
        FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3321
3322
        p->flowflags = FLOW_PKT_TOCLIENT;
3323
        p->payload = NULL;
3324
        p->payload_len = 0;
3325
        tcph.th_seq = htonl(572799782UL);
3326
        tcph.th_ack = htonl(ssn.client.isn + 1 + cnt);
3327
        tcph.th_flags = TH_ACK;
3328
        p->tcph = &tcph;
3329
        s = &ssn.server;
3330
3331
        FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3332
    }
3333
3334
    FAIL_IF(f->alproto != ALPROTO_HTTP1);
3335
3336
    StreamTcpUTClearSession(&ssn);
3337
    StreamTcpReassembleFreeThreadCtx(ra_ctx);
3338
    StreamTcpFreeConfig(true);
3339
    SCFree(p);
3340
    UTHFreeFlow(f);
3341
    PASS;
3342
}
3343
3344
/** \test 3 in order segments in inline reassembly */
3345
static int StreamTcpReassembleInlineTest01(void)
3346
{
3347
    int ret = 0;
3348
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3349
    ThreadVars tv;
3350
    TcpSession ssn;
3351
    Flow f;
3352
3353
    memset(&tv, 0x00, sizeof(tv));
3354
3355
    StreamTcpUTInit(&ra_ctx);
3356
    StreamTcpUTInitInline();
3357
    StreamTcpUTSetupSession(&ssn);
3358
    StreamTcpUTSetupStream(&ssn.client, 1);
3359
    FLOW_INITIALIZE(&f);
3360
3361
    uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3362
    Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3363
    if (p == NULL) {
3364
        printf("couldn't get a packet: ");
3365
        goto end;
3366
    }
3367
    p->tcph->th_seq = htonl(12);
3368
    p->flow = &f;
3369
3370
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1) {
3371
        printf("failed to add segment 1: ");
3372
        goto end;
3373
    }
3374
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1) {
3375
        printf("failed to add segment 2: ");
3376
        goto end;
3377
    }
3378
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3379
        printf("failed to add segment 3: ");
3380
        goto end;
3381
    }
3382
    ssn.client.next_seq = 17;
3383
    ret = 1;
3384
end:
3385
    FLOW_DESTROY(&f);
3386
    UTHFreePacket(p);
3387
    StreamTcpUTClearSession(&ssn);
3388
    StreamTcpUTDeinit(ra_ctx);
3389
    return ret;
3390
}
3391
3392
/** \test 3 in order segments, then reassemble, add one more and reassemble again.
3393
 *        test the sliding window reassembly.
3394
 */
3395
static int StreamTcpReassembleInlineTest02(void)
3396
{
3397
    int ret = 0;
3398
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3399
    ThreadVars tv;
3400
    TcpSession ssn;
3401
    Flow f;
3402
3403
    memset(&tv, 0x00, sizeof(tv));
3404
3405
    StreamTcpUTInit(&ra_ctx);
3406
    StreamTcpUTInitInline();
3407
    StreamTcpUTSetupSession(&ssn);
3408
    StreamTcpUTSetupStream(&ssn.client, 1);
3409
    FLOW_INITIALIZE(&f);
3410
3411
    uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3412
    Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3413
    if (p == NULL) {
3414
        printf("couldn't get a packet: ");
3415
        goto end;
3416
    }
3417
    p->tcph->th_seq = htonl(12);
3418
    p->flow = &f;
3419
3420
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1) {
3421
        printf("failed to add segment 1: ");
3422
        goto end;
3423
    }
3424
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1) {
3425
        printf("failed to add segment 2: ");
3426
        goto end;
3427
    }
3428
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3429
        printf("failed to add segment 3: ");
3430
        goto end;
3431
    }
3432
    ssn.client.next_seq = 17;
3433
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3434
        printf("failed to add segment 4: ");
3435
        goto end;
3436
    }
3437
    ssn.client.next_seq = 22;
3438
    ret = 1;
3439
end:
3440
    FLOW_DESTROY(&f);
3441
    UTHFreePacket(p);
3442
    StreamTcpUTClearSession(&ssn);
3443
    StreamTcpUTDeinit(ra_ctx);
3444
    return ret;
3445
}
3446
3447
/** \test 3 in order segments, then reassemble, add one more and reassemble again.
3448
 *        test the sliding window reassembly with a small window size so that we
3449
 *        cutting off at the start (left edge)
3450
 */
3451
static int StreamTcpReassembleInlineTest03(void)
3452
{
3453
    int ret = 0;
3454
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3455
    ThreadVars tv;
3456
    TcpSession ssn;
3457
    Flow f;
3458
3459
    memset(&tv, 0x00, sizeof(tv));
3460
3461
    StreamTcpUTInit(&ra_ctx);
3462
    StreamTcpUTInitInline();
3463
    StreamTcpUTSetupSession(&ssn);
3464
    StreamTcpUTSetupStream(&ssn.client, 1);
3465
    FLOW_INITIALIZE(&f);
3466
3467
    stream_config.reassembly_toserver_chunk_size = 15;
3468
3469
    uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3470
    Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3471
    if (p == NULL) {
3472
        printf("couldn't get a packet: ");
3473
        goto end;
3474
    }
3475
    p->tcph->th_seq = htonl(12);
3476
    p->flow = &f;
3477
    p->flowflags |= FLOW_PKT_TOSERVER;
3478
3479
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1) {
3480
        printf("failed to add segment 1: ");
3481
        goto end;
3482
    }
3483
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1) {
3484
        printf("failed to add segment 2: ");
3485
        goto end;
3486
    }
3487
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3488
        printf("failed to add segment 3: ");
3489
        goto end;
3490
    }
3491
    ssn.client.next_seq = 17;
3492
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3493
        printf("failed to add segment 4: ");
3494
        goto end;
3495
    }
3496
    ssn.client.next_seq = 22;
3497
3498
    p->tcph->th_seq = htonl(17);
3499
    ret = 1;
3500
end:
3501
    FLOW_DESTROY(&f);
3502
    UTHFreePacket(p);
3503
    StreamTcpUTClearSession(&ssn);
3504
    StreamTcpUTDeinit(ra_ctx);
3505
    return ret;
3506
}
3507
3508
/** \test 3 in order segments, then reassemble, add one more and reassemble again.
3509
 *        test the sliding window reassembly with a small window size so that we
3510
 *        cutting off at the start (left edge) with small packet overlap.
3511
 */
3512
static int StreamTcpReassembleInlineTest04(void)
3513
{
3514
    int ret = 0;
3515
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3516
    ThreadVars tv;
3517
    TcpSession ssn;
3518
    Flow f;
3519
3520
    memset(&tv, 0x00, sizeof(tv));
3521
3522
    StreamTcpUTInit(&ra_ctx);
3523
    StreamTcpUTInitInline();
3524
    StreamTcpUTSetupSession(&ssn);
3525
    StreamTcpUTSetupStream(&ssn.client, 1);
3526
    FLOW_INITIALIZE(&f);
3527
3528
    stream_config.reassembly_toserver_chunk_size = 16;
3529
3530
    uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3531
    Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3532
    if (p == NULL) {
3533
        printf("couldn't get a packet: ");
3534
        goto end;
3535
    }
3536
    p->tcph->th_seq = htonl(12);
3537
    p->flow = &f;
3538
    p->flowflags |= FLOW_PKT_TOSERVER;
3539
3540
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1) {
3541
        printf("failed to add segment 1: ");
3542
        goto end;
3543
    }
3544
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1) {
3545
        printf("failed to add segment 2: ");
3546
        goto end;
3547
    }
3548
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3549
        printf("failed to add segment 3: ");
3550
        goto end;
3551
    }
3552
    ssn.client.next_seq = 17;
3553
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3554
        printf("failed to add segment 4: ");
3555
        goto end;
3556
    }
3557
    ssn.client.next_seq = 22;
3558
3559
    p->tcph->th_seq = htonl(17);
3560
    ret = 1;
3561
end:
3562
    FLOW_DESTROY(&f);
3563
    UTHFreePacket(p);
3564
    StreamTcpUTClearSession(&ssn);
3565
    StreamTcpUTDeinit(ra_ctx);
3566
    return ret;
3567
}
3568
3569
/** \test 3 in order segments, then reassemble, add one more and reassemble again.
3570
 *        test the sliding window reassembly with a small window size so that we
3571
 *        cutting off at the start (left edge). Test if the first segment is
3572
 *        removed from the list.
3573
 */
3574
static int StreamTcpReassembleInlineTest08(void)
3575
{
3576
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3577
    ThreadVars tv;
3578
    memset(&tv, 0x00, sizeof(tv));
3579
    TcpSession ssn;
3580
    Flow f;
3581
    StreamTcpUTInit(&ra_ctx);
3582
    StreamTcpUTInitInline();
3583
    StreamTcpUTSetupSession(&ssn);
3584
    StreamTcpUTSetupStream(&ssn.client, 1);
3585
    FLOW_INITIALIZE(&f);
3586
3587
    stream_config.reassembly_toserver_chunk_size = 15;
3588
    f.protoctx = &ssn;
3589
3590
    uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3591
    Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3592
    FAIL_IF(p == NULL);
3593
    p->tcph->th_seq = htonl(12);
3594
    p->flow = &f;
3595
    p->flowflags |= FLOW_PKT_TOSERVER;
3596
3597
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1);
3598
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1);
3599
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3600
    ssn.client.next_seq = 17;
3601
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
3602
    ssn.client.next_seq = 22;
3603
    p->tcph->th_seq = htonl(17);
3604
    StreamTcpPruneSession(&f, STREAM_TOSERVER);
3605
3606
    TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3607
    FAIL_IF_NULL(seg);
3608
    FAIL_IF_NOT(seg->seq == 2);
3609
3610
    FLOW_DESTROY(&f);
3611
    UTHFreePacket(p);
3612
    StreamTcpUTClearSession(&ssn);
3613
    StreamTcpUTDeinit(ra_ctx);
3614
    PASS;
3615
}
3616
3617
/** \test 3 in order segments, then reassemble, add one more and reassemble again.
3618
 *        test the sliding window reassembly with a small window size so that we
3619
 *        cutting off at the start (left edge). Test if the first segment is
3620
 *        removed from the list.
3621
 */
3622
static int StreamTcpReassembleInlineTest09(void)
3623
{
3624
    int ret = 0;
3625
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3626
    ThreadVars tv;
3627
    TcpSession ssn;
3628
    Flow f;
3629
3630
    memset(&tv, 0x00, sizeof(tv));
3631
3632
    StreamTcpUTInit(&ra_ctx);
3633
    StreamTcpUTInitInline();
3634
    StreamTcpUTSetupSession(&ssn);
3635
    StreamTcpUTSetupStream(&ssn.client, 1);
3636
    FLOW_INITIALIZE(&f);
3637
3638
    stream_config.reassembly_toserver_chunk_size = 20;
3639
3640
    uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3641
    Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3642
    if (p == NULL) {
3643
        printf("couldn't get a packet: ");
3644
        goto end;
3645
    }
3646
    p->tcph->th_seq = htonl(17);
3647
    p->flow = &f;
3648
    p->flowflags |= FLOW_PKT_TOSERVER;
3649
3650
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1) {
3651
        printf("failed to add segment 1: ");
3652
        goto end;
3653
    }
3654
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1) {
3655
        printf("failed to add segment 2: ");
3656
        goto end;
3657
    }
3658
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3659
        printf("failed to add segment 3: ");
3660
        goto end;
3661
    }
3662
    ssn.client.next_seq = 12;
3663
    ssn.client.last_ack = 10;
3664
3665
    /* close the GAP and see if we properly reassemble and update base_seq */
3666
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3667
        printf("failed to add segment 4: ");
3668
        goto end;
3669
    }
3670
    ssn.client.next_seq = 22;
3671
3672
    p->tcph->th_seq = htonl(12);
3673
3674
    TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3675
    FAIL_IF_NULL(seg);
3676
    FAIL_IF_NOT(seg->seq == 2);
3677
3678
    ret = 1;
3679
end:
3680
    FLOW_DESTROY(&f);
3681
    UTHFreePacket(p);
3682
    StreamTcpUTClearSession(&ssn);
3683
    StreamTcpUTDeinit(ra_ctx);
3684
    return ret;
3685
}
3686
3687
/** \test App Layer reassembly.
3688
 */
3689
static int StreamTcpReassembleInlineTest10(void)
3690
{
3691
    int ret = 0;
3692
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3693
    ThreadVars tv;
3694
    TcpSession ssn;
3695
    Flow *f = NULL;
3696
    Packet *p = NULL;
3697
3698
    memset(&tv, 0x00, sizeof(tv));
3699
3700
    StreamTcpUTInit(&ra_ctx);
3701
    StreamTcpUTInitInline();
3702
    StreamTcpUTSetupSession(&ssn);
3703
    StreamTcpUTSetupStream(&ssn.server, 1);
3704
    ssn.server.last_ack = 2;
3705
    StreamTcpUTSetupStream(&ssn.client, 1);
3706
    ssn.client.last_ack = 2;
3707
    ssn.data_first_seen_dir = STREAM_TOSERVER;
3708
3709
    f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
3710
    if (f == NULL)
3711
        goto end;
3712
    f->protoctx = &ssn;
3713
    f->proto = IPPROTO_TCP;
3714
3715
    uint8_t stream_payload1[] = "GE";
3716
    uint8_t stream_payload2[] = "T /";
3717
    uint8_t stream_payload3[] = "HTTP/1.0\r\n\r\n";
3718
3719
    p = UTHBuildPacketReal(stream_payload3, 12, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3720
    if (p == NULL) {
3721
        printf("couldn't get a packet: ");
3722
        goto end;
3723
    }
3724
    p->tcph->th_seq = htonl(7);
3725
    p->flow = f;
3726
    p->flowflags = FLOW_PKT_TOSERVER;
3727
3728
    if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client,  2, stream_payload1, 2) == -1) {
3729
        printf("failed to add segment 1: ");
3730
        goto end;
3731
    }
3732
    ssn.client.next_seq = 4;
3733
3734
    int r = StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET);
3735
    if (r < 0) {
3736
        printf("StreamTcpReassembleAppLayer failed: ");
3737
        goto end;
3738
    }
3739
3740
    /* ssn.server.ra_app_base_seq should be isn here. */
3741
    if (ssn.client.base_seq != 2 || ssn.client.base_seq != ssn.client.isn+1) {
3742
        printf("expected ra_app_base_seq 1, got %u: ", ssn.client.base_seq);
3743
        goto end;
3744
    }
3745
3746
    if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client,  4, stream_payload2, 3) == -1) {
3747
        printf("failed to add segment 2: ");
3748
        goto end;
3749
    }
3750
    if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client,  7, stream_payload3, 12) == -1) {
3751
        printf("failed to add segment 3: ");
3752
        goto end;
3753
    }
3754
    ssn.client.next_seq = 19;
3755
3756
    r = StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET);
3757
    if (r < 0) {
3758
        printf("StreamTcpReassembleAppLayer failed: ");
3759
        goto end;
3760
    }
3761
3762
    FAIL_IF_NOT(STREAM_APP_PROGRESS(&ssn.client) == 17);
3763
3764
    ret = 1;
3765
end:
3766
    UTHFreePacket(p);
3767
    StreamTcpUTClearSession(&ssn);
3768
    StreamTcpUTDeinit(ra_ctx);
3769
    UTHFreeFlow(f);
3770
    return ret;
3771
}
3772
3773
/** \test test insert with overlap
3774
 */
3775
static int StreamTcpReassembleInsertTest01(void)
3776
{
3777
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3778
    ThreadVars tv;
3779
    TcpSession ssn;
3780
    Flow f;
3781
3782
    memset(&tv, 0x00, sizeof(tv));
3783
3784
    StreamTcpUTInit(&ra_ctx);
3785
    StreamTcpUTSetupSession(&ssn);
3786
    StreamTcpUTSetupStream(&ssn.client, 1);
3787
    ssn.client.os_policy = OS_POLICY_LAST;
3788
    FLOW_INITIALIZE(&f);
3789
3790
    uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3791
    Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3792
    FAIL_IF(p == NULL);
3793
    p->tcph->th_seq = htonl(12);
3794
    p->flow = &f;
3795
3796
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 5) == -1);
3797
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  7, 'B', 5) == -1);
3798
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 14, 'D', 2) == -1);
3799
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 16, 'D', 6) == -1);
3800
    FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3801
    ssn.client.next_seq = 21;
3802
3803
    FLOW_DESTROY(&f);
3804
    UTHFreePacket(p);
3805
    StreamTcpUTClearSession(&ssn);
3806
    StreamTcpUTDeinit(ra_ctx);
3807
    PASS;
3808
}
3809
3810
/** \test test insert with overlaps
3811
 */
3812
static int StreamTcpReassembleInsertTest02(void)
3813
{
3814
    int ret = 0;
3815
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3816
    ThreadVars tv;
3817
    TcpSession ssn;
3818
3819
    memset(&tv, 0x00, sizeof(tv));
3820
3821
    StreamTcpUTInit(&ra_ctx);
3822
    StreamTcpUTSetupSession(&ssn);
3823
    StreamTcpUTSetupStream(&ssn.client, 1);
3824
3825
    int i;
3826
    for (i = 2; i < 10; i++) {
3827
        int len;
3828
        len = i % 2;
3829
        if (len == 0)
3830
            len = 1;
3831
        int seq;
3832
        seq = i * 10;
3833
        if (seq < 2)
3834
            seq = 2;
3835
3836
        if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  seq, 'A', len) == -1) {
3837
            printf("failed to add segment 1: ");
3838
            goto end;
3839
        }
3840
    }
3841
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'B', 1024) == -1) {
3842
        printf("failed to add segment 2: ");
3843
        goto end;
3844
    }
3845
3846
    ret = 1;
3847
end:
3848
    StreamTcpUTClearSession(&ssn);
3849
    StreamTcpUTDeinit(ra_ctx);
3850
    return ret;
3851
}
3852
3853
/** \test test insert with overlaps
3854
 */
3855
static int StreamTcpReassembleInsertTest03(void)
3856
{
3857
    int ret = 0;
3858
    TcpReassemblyThreadCtx *ra_ctx = NULL;
3859
    ThreadVars tv;
3860
    TcpSession ssn;
3861
3862
    memset(&tv, 0x00, sizeof(tv));
3863
3864
    StreamTcpUTInit(&ra_ctx);
3865
    StreamTcpUTSetupSession(&ssn);
3866
    StreamTcpUTSetupStream(&ssn.client, 1);
3867
3868
    if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  2, 'A', 1024) == -1) {
3869
        printf("failed to add segment 2: ");
3870
        goto end;
3871
    }
3872
3873
    int i;
3874
    for (i = 2; i < 10; i++) {
3875
        int len;
3876
        len = i % 2;
3877
        if (len == 0)
3878
            len = 1;
3879
        int seq;
3880
        seq = i * 10;
3881
        if (seq < 2)
3882
            seq = 2;
3883
3884
        if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client,  seq, 'B', len) == -1) {
3885
            printf("failed to add segment 2: ");
3886
            goto end;
3887
        }
3888
    }
3889
    ret = 1;
3890
end:
3891
    StreamTcpUTClearSession(&ssn);
3892
    StreamTcpUTDeinit(ra_ctx);
3893
    return ret;
3894
}
3895
3896
#include "tests/stream-tcp-reassemble.c"
3897
#endif /* UNITTESTS */
3898
3899
/** \brief  The Function Register the Unit tests to test the reassembly engine
3900
 *          for various OS policies.
3901
 */
3902
3903
void StreamTcpReassembleRegisterTests(void)
3904
0
{
3905
#ifdef UNITTESTS
3906
    UtRegisterTest("StreamTcpReassembleTest25 -- Gap at Start Reassembly Test",
3907
                   StreamTcpReassembleTest25);
3908
    UtRegisterTest("StreamTcpReassembleTest26 -- Gap at middle Reassembly Test",
3909
                   StreamTcpReassembleTest26);
3910
    UtRegisterTest("StreamTcpReassembleTest27 -- Gap at after  Reassembly Test",
3911
                   StreamTcpReassembleTest27);
3912
    UtRegisterTest("StreamTcpReassembleTest28 -- Gap at Start IDS missed packet Reassembly Test",
3913
                   StreamTcpReassembleTest28);
3914
    UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test",
3915
                   StreamTcpReassembleTest29);
3916
    UtRegisterTest("StreamTcpReassembleTest33 -- Bug test",
3917
                   StreamTcpReassembleTest33);
3918
    UtRegisterTest("StreamTcpReassembleTest34 -- Bug test",
3919
                   StreamTcpReassembleTest34);
3920
    UtRegisterTest("StreamTcpReassembleTest39 -- app proto test",
3921
                   StreamTcpReassembleTest39);
3922
    UtRegisterTest("StreamTcpReassembleTest40 -- app proto test",
3923
                   StreamTcpReassembleTest40);
3924
    UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test",
3925
                   StreamTcpReassembleTest44);
3926
    UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test",
3927
                   StreamTcpReassembleTest45);
3928
    UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test",
3929
                   StreamTcpReassembleTest46);
3930
    UtRegisterTest("StreamTcpReassembleTest47 -- TCP Sequence Wraparound Test",
3931
                   StreamTcpReassembleTest47);
3932
3933
    UtRegisterTest("StreamTcpReassembleInlineTest01 -- inline RAW ra",
3934
                   StreamTcpReassembleInlineTest01);
3935
    UtRegisterTest("StreamTcpReassembleInlineTest02 -- inline RAW ra 2",
3936
                   StreamTcpReassembleInlineTest02);
3937
    UtRegisterTest("StreamTcpReassembleInlineTest03 -- inline RAW ra 3",
3938
                   StreamTcpReassembleInlineTest03);
3939
    UtRegisterTest("StreamTcpReassembleInlineTest04 -- inline RAW ra 4",
3940
                   StreamTcpReassembleInlineTest04);
3941
    UtRegisterTest("StreamTcpReassembleInlineTest08 -- inline RAW ra 8 cleanup",
3942
                   StreamTcpReassembleInlineTest08);
3943
    UtRegisterTest("StreamTcpReassembleInlineTest09 -- inline RAW ra 9 GAP cleanup",
3944
                   StreamTcpReassembleInlineTest09);
3945
3946
    UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10",
3947
                   StreamTcpReassembleInlineTest10);
3948
3949
    UtRegisterTest("StreamTcpReassembleInsertTest01 -- insert with overlap",
3950
                   StreamTcpReassembleInsertTest01);
3951
    UtRegisterTest("StreamTcpReassembleInsertTest02 -- insert with overlap",
3952
                   StreamTcpReassembleInsertTest02);
3953
    UtRegisterTest("StreamTcpReassembleInsertTest03 -- insert with overlap",
3954
                   StreamTcpReassembleInsertTest03);
3955
3956
    StreamTcpInlineRegisterTests();
3957
    StreamTcpUtilRegisterTests();
3958
    StreamTcpListRegisterTests();
3959
    StreamTcpReassembleRawRegisterTests();
3960
#endif /* UNITTESTS */
3961
0
}