suricata
stream-tcp-reassemble.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2021 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18#include "../suricata-common.h"
19#include "../stream-tcp-private.h"
20#include "../stream-tcp.h"
21#include "../stream-tcp-reassemble.h"
22#include "../stream-tcp-inline.h"
23#include "../stream-tcp-list.h"
24#include "../stream-tcp-util.h"
25#include "../util-streaming-buffer.h"
26#include "../util-print.h"
27#include "../util-unittest.h"
28
30 const uint8_t *expect_data;
31 const uint32_t expect_data_len;
32};
33
34static int TestReassembleRawCallback(
35 void *cb_data, const uint8_t *data, const uint32_t data_len, const uint64_t offset)
36{
37 struct TestReassembleRawCallbackData *cb = cb_data;
38
39 SCLogNotice("have %u expect %u", data_len, cb->expect_data_len);
40
41 if (data_len == cb->expect_data_len &&
42 memcmp(data, cb->expect_data, data_len) == 0) {
43 return 1;
44 } else {
45 SCLogNotice("data mismatch. Expected:");
47 SCLogNotice("Got:");
48 PrintRawDataFp(stdout, data, data_len);
49 return -1;
50 }
51}
52
53static int TestReassembleRawValidate(TcpSession *ssn, Packet *p,
54 const uint8_t *data, const uint32_t data_len)
55{
56 struct TestReassembleRawCallbackData cb = { data, data_len };
57 uint64_t progress = 0;
58 int r = StreamReassembleRaw(ssn, p, TestReassembleRawCallback, &cb, &progress, false);
59 if (r == 1) {
60 StreamReassembleRawUpdateProgress(ssn, p, progress);
61 }
62 SCLogNotice("r %d", r);
63 return r;
64}
65
66#define RAWREASSEMBLY_START(isn) \
67 TcpReassemblyThreadCtx *ra_ctx = NULL; \
68 TcpSession ssn; \
69 ThreadVars tv; \
70 memset(&tv, 0, sizeof(tv)); \
71 Packet *p = NULL; \
72 \
73 \
74 StreamTcpUTInit(&ra_ctx); \
75 StreamTcpUTInitInline(); \
76 stream_config.reassembly_toserver_chunk_size = 9; \
77 stream_config.reassembly_toclient_chunk_size = 9; \
78 StreamTcpUTSetupSession(&ssn); \
79 StreamTcpUTSetupStream(&ssn.server, (isn)); \
80 StreamTcpUTSetupStream(&ssn.client, (isn)); \
81 ssn.server.last_ack = (isn) + 1; \
82 ssn.client.last_ack = (isn) + 1; \
83 \
84 TcpStream *stream = &ssn.client;
85
86#define RAWREASSEMBLY_END \
87 StreamTcpUTClearSession(&ssn); \
88 StreamTcpUTDeinit(ra_ctx); \
89 PASS
90
91#define RAWREASSEMBLY_STEP(seq, seg, seglen, buf, buflen) \
92 p = PacketGetFromAlloc(); \
93 FAIL_IF_NULL(p); \
94 { \
95 SCLogNotice("SEQ %u block of %u", (seq), (seglen)); \
96 p->flowflags = FLOW_PKT_TOSERVER; \
97 TCPHdr tcphdr; \
98 memset(&tcphdr, 0, sizeof(tcphdr)); \
99 UTHSetTCPHdr(p, &tcphdr); \
100 tcphdr.th_seq = htonl((seq)); \
101 tcphdr.th_ack = htonl(10); \
102 p->payload_len = (seglen); \
103 \
104 FAIL_IF(StreamTcpUTAddPayload( \
105 &tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen)) != 0); \
106 p->flags |= PKT_STREAM_ADD; \
107 FAIL_IF(!(TestReassembleRawValidate(&ssn, p, (uint8_t *)(buf), (buflen)))); \
108 } \
109 PacketFree(p);
110
111#define RAWREASSEMBLY_STEP_WITH_PROGRESS(seq, seg, seglen, buf, buflen, lastack, progress) \
112 stream->last_ack = (lastack); \
113 RAWREASSEMBLY_STEP((seq),(seg),(seglen),(buf),(buflen)); \
114 FAIL_IF(STREAM_RAW_PROGRESS(stream) != (progress));
115
116static int StreamTcpReassembleRawTest01 (void)
117{
119 RAWREASSEMBLY_STEP(2, "AAA", 3, "AAA", 3);
120 RAWREASSEMBLY_STEP(5, "BBB", 3, "AAABBB", 6);
121 RAWREASSEMBLY_STEP(8, "CCC", 3, "AAABBBCCC", 9);
123}
124
125static int StreamTcpReassembleRawTest02 (void)
126{
128 RAWREASSEMBLY_STEP(2, "AAA", 3, "AAA", 3);
129 RAWREASSEMBLY_STEP(5, "BBB", 3, "AAABBB", 6);
130 RAWREASSEMBLY_STEP(11,"DDD", 3, "DDD", 3);
131 RAWREASSEMBLY_STEP(8, "CCC", 3, "BBBCCCDDD", 9);
133}
134
135static int StreamTcpReassembleRawTest03 (void)
136{
138 RAWREASSEMBLY_STEP(2, "AAA", 3, "AAA", 3);
139 RAWREASSEMBLY_STEP(11,"DDD", 3, "DDD", 3);
140 RAWREASSEMBLY_STEP(8, "CCC", 3, "CCCDDD", 6);
142}
143
144static int StreamTcpReassembleRawTest04 (void)
145{
147 RAWREASSEMBLY_STEP(2, "AAAAA", 5, "AAAAA", 5);
148 RAWREASSEMBLY_STEP(10,"CCCCC", 5, "CCCCC", 5);
149 RAWREASSEMBLY_STEP(7, "BBB", 3, "AAABBBCCC", 9);
151}
152
153static int StreamTcpReassembleRawTest05 (void)
154{
156 RAWREASSEMBLY_STEP(2, "AAAAA", 5, "AAAAA", 5);
157 RAWREASSEMBLY_STEP(10,"CCCCC", 5, "CCCCC", 5);
158 RAWREASSEMBLY_STEP(2, "EEEEEEEEEEEEE", 13, "AAAAAEEECCCCC", 13);
160}
161
162static int StreamTcpReassembleRawTest06 (void)
163{
165 RAWREASSEMBLY_STEP(2, "AAAAA", 5, "AAAAA", 5);
166 RAWREASSEMBLY_STEP(16,"CCCCC", 5, "CCCCC", 5);
167 RAWREASSEMBLY_STEP(7, "BBBBBBBBB", 9, "ABBBBBBBBBC", 11);
168 RAWREASSEMBLY_STEP(21,"DDDDDDDDDD",10,"CCCDDDDDDDDDD", 13);
170}
171
172static int StreamTcpReassembleRawTest07 (void)
173{
175 RAWREASSEMBLY_STEP(2, "AAAAAAA", 7, "AAAAAAA", 7);
176 RAWREASSEMBLY_STEP(9, "BBBBBBB", 7, "AAABBBBBBB", 10);
177 RAWREASSEMBLY_STEP(16,"C", 1, "ABBBBBBBC", 9);
178 RAWREASSEMBLY_STEP(17,"DDDDDDDD",8,"BBCDDDDDDDD", 11);
180}
181
182static int StreamTcpReassembleRawTest08 (void)
183{
185 RAWREASSEMBLY_STEP_WITH_PROGRESS(2, "AAA", 3, "AAA", 3, 3, 3);
186 RAWREASSEMBLY_STEP_WITH_PROGRESS(8, "CCC", 3, "CCC", 3, 3, 3);
187 // segment lost, last_ack updated
188 RAWREASSEMBLY_STEP_WITH_PROGRESS(11, "DDD", 3, "CCCDDD", 6, 8, 12);
190}
191
192static void StreamTcpReassembleRawRegisterTests(void)
193{
194 UtRegisterTest("StreamTcpReassembleRawTest01",
195 StreamTcpReassembleRawTest01);
196 UtRegisterTest("StreamTcpReassembleRawTest02",
197 StreamTcpReassembleRawTest02);
198 UtRegisterTest("StreamTcpReassembleRawTest03",
199 StreamTcpReassembleRawTest03);
200 UtRegisterTest("StreamTcpReassembleRawTest04",
201 StreamTcpReassembleRawTest04);
202 UtRegisterTest("StreamTcpReassembleRawTest05",
203 StreamTcpReassembleRawTest05);
204 UtRegisterTest("StreamTcpReassembleRawTest06",
205 StreamTcpReassembleRawTest06);
206 UtRegisterTest("StreamTcpReassembleRawTest07",
207 StreamTcpReassembleRawTest07);
208 UtRegisterTest("StreamTcpReassembleRawTest08",
209 StreamTcpReassembleRawTest08);
210}
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
int StreamReassembleRaw(TcpSession *ssn, const Packet *p, StreamReassembleRawFunc Callback, void *cb_data, uint64_t *progress_out, bool respect_inspect_depth)
void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, const uint64_t progress)
update stream engine after detection
#define RAWREASSEMBLY_START(isn)
#define RAWREASSEMBLY_END
#define RAWREASSEMBLY_STEP(seq, seg, seglen, buf, buflen)
#define RAWREASSEMBLY_STEP_WITH_PROGRESS(seq, seg, seglen, buf, buflen, lastack, progress)
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition util-debug.h:243
void PrintRawDataFp(FILE *fp, const uint8_t *buf, uint32_t buflen)
Definition util-print.c:112
uint64_t offset