suricata
stream-tcp-reassemble.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2017 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 
34 static int TestReassembleRawCallback(void *cb_data, const uint8_t *data, const uint32_t data_len)
35 {
36  struct TestReassembleRawCallbackData *cb = cb_data;
37 
38  SCLogNotice("have %u expect %u", data_len, cb->expect_data_len);
39 
40  if (data_len == cb->expect_data_len &&
41  memcmp(data, cb->expect_data, data_len) == 0) {
42  return 1;
43  } else {
44  SCLogNotice("data mismatch. Expected:");
45  PrintRawDataFp(stdout, cb->expect_data, cb->expect_data_len);
46  SCLogNotice("Got:");
47  PrintRawDataFp(stdout, data, data_len);
48  return -1;
49  }
50 }
51 
52 static int TestReassembleRawValidate(TcpSession *ssn, Packet *p,
53  const uint8_t *data, const uint32_t data_len)
54 {
55  struct TestReassembleRawCallbackData cb = { data, data_len };
56  uint64_t progress = 0;
57  int r = StreamReassembleRaw(ssn, p, TestReassembleRawCallback, &cb, &progress, false);
58  if (r == 1) {
59  StreamReassembleRawUpdateProgress(ssn, p, progress);
60  }
61  SCLogNotice("r %d", r);
62  return r;
63 }
64 
65 #define RAWREASSEMBLY_START(isn) \
66  TcpReassemblyThreadCtx *ra_ctx = NULL; \
67  TcpSession ssn; \
68  ThreadVars tv; \
69  memset(&tv, 0, sizeof(tv)); \
70  Packet *p = NULL; \
71  \
72  \
73  StreamTcpUTInit(&ra_ctx); \
74  StreamTcpUTInitInline(); \
75  stream_config.reassembly_toserver_chunk_size = 9; \
76  stream_config.reassembly_toclient_chunk_size = 9; \
77  StreamTcpUTSetupSession(&ssn); \
78  StreamTcpUTSetupStream(&ssn.server, (isn)); \
79  StreamTcpUTSetupStream(&ssn.client, (isn)); \
80  ssn.server.last_ack = (isn) + 1; \
81  ssn.client.last_ack = (isn) + 1; \
82  \
83  TcpStream *stream = &ssn.client;
84 
85 #define RAWREASSEMBLY_END \
86  StreamTcpUTClearSession(&ssn); \
87  StreamTcpUTDeinit(ra_ctx); \
88  PASS
89 
90 #define RAWREASSEMBLY_STEP(seq, seg, seglen, buf, buflen) \
91  p = PacketGetFromAlloc(); \
92  FAIL_IF_NULL(p); \
93  { \
94  SCLogNotice("SEQ %u block of %u", (seq), (seglen)); \
95  p->flowflags = FLOW_PKT_TOSERVER; \
96  TCPHdr tcphdr; \
97  memset(&tcphdr, 0, sizeof(tcphdr)); \
98  p->tcph = &tcphdr; \
99  p->tcph->th_seq = htonl((seq)); \
100  p->tcph->th_ack = htonl(10); \
101  p->payload_len = (seglen); \
102  \
103  FAIL_IF(StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen)) != 0); \
104  p->flags |= PKT_STREAM_ADD; \
105  FAIL_IF(!(TestReassembleRawValidate(&ssn, p, (uint8_t *)(buf), (buflen)))); \
106  }\
107  PacketFree(p);
108 
109 #define RAWREASSEMBLY_STEP_WITH_PROGRESS(seq, seg, seglen, buf, buflen, lastack, progress) \
110  stream->last_ack = (lastack); \
111  RAWREASSEMBLY_STEP((seq),(seg),(seglen),(buf),(buflen)); \
112  FAIL_IF(STREAM_RAW_PROGRESS(stream) != (progress));
113 
114 static int StreamTcpReassembleRawTest01 (void)
115 {
117  RAWREASSEMBLY_STEP(2, "AAA", 3, "AAA", 3);
118  RAWREASSEMBLY_STEP(5, "BBB", 3, "AAABBB", 6);
119  RAWREASSEMBLY_STEP(8, "CCC", 3, "AAABBBCCC", 9);
121 }
122 
123 static int StreamTcpReassembleRawTest02 (void)
124 {
126  RAWREASSEMBLY_STEP(2, "AAA", 3, "AAA", 3);
127  RAWREASSEMBLY_STEP(5, "BBB", 3, "AAABBB", 6);
128  RAWREASSEMBLY_STEP(11,"DDD", 3, "DDD", 3);
129  RAWREASSEMBLY_STEP(8, "CCC", 3, "BBBCCCDDD", 9);
131 }
132 
133 static int StreamTcpReassembleRawTest03 (void)
134 {
136  RAWREASSEMBLY_STEP(2, "AAA", 3, "AAA", 3);
137  RAWREASSEMBLY_STEP(11,"DDD", 3, "DDD", 3);
138  RAWREASSEMBLY_STEP(8, "CCC", 3, "CCCDDD", 6);
140 }
141 
142 static int StreamTcpReassembleRawTest04 (void)
143 {
145  RAWREASSEMBLY_STEP(2, "AAAAA", 5, "AAAAA", 5);
146  RAWREASSEMBLY_STEP(10,"CCCCC", 5, "CCCCC", 5);
147  RAWREASSEMBLY_STEP(7, "BBB", 3, "AAABBBCCC", 9);
149 }
150 
151 static int StreamTcpReassembleRawTest05 (void)
152 {
154  RAWREASSEMBLY_STEP(2, "AAAAA", 5, "AAAAA", 5);
155  RAWREASSEMBLY_STEP(10,"CCCCC", 5, "CCCCC", 5);
156  RAWREASSEMBLY_STEP(2, "EEEEEEEEEEEEE", 13, "AAAAAEEECCCCC", 13);
158 }
159 
160 static int StreamTcpReassembleRawTest06 (void)
161 {
163  RAWREASSEMBLY_STEP(2, "AAAAA", 5, "AAAAA", 5);
164  RAWREASSEMBLY_STEP(16,"CCCCC", 5, "CCCCC", 5);
165  RAWREASSEMBLY_STEP(7, "BBBBBBBBB", 9, "ABBBBBBBBBC", 11);
166  RAWREASSEMBLY_STEP(21,"DDDDDDDDDD",10,"CCCDDDDDDDDDD", 13);
168 }
169 
170 static int StreamTcpReassembleRawTest07 (void)
171 {
173  RAWREASSEMBLY_STEP(2, "AAAAAAA", 7, "AAAAAAA", 7);
174  RAWREASSEMBLY_STEP(9, "BBBBBBB", 7, "AAABBBBBBB", 10);
175  RAWREASSEMBLY_STEP(16,"C", 1, "ABBBBBBBC", 9);
176  RAWREASSEMBLY_STEP(17,"DDDDDDDD",8,"BBCDDDDDDDD", 11);
178 }
179 
180 static int StreamTcpReassembleRawTest08 (void)
181 {
183  RAWREASSEMBLY_STEP_WITH_PROGRESS(2, "AAA", 3, "AAA", 3, 3, 3);
184  RAWREASSEMBLY_STEP_WITH_PROGRESS(8, "CCC", 3, "CCC", 3, 3, 3);
185  // segment lost, last_ack updated
186  RAWREASSEMBLY_STEP_WITH_PROGRESS(11, "DDD", 3, "CCCDDD", 6, 8, 12);
188 }
189 
190 static void StreamTcpReassembleRawRegisterTests(void)
191 {
192  UtRegisterTest("StreamTcpReassembleRawTest01",
193  StreamTcpReassembleRawTest01);
194  UtRegisterTest("StreamTcpReassembleRawTest02",
195  StreamTcpReassembleRawTest02);
196  UtRegisterTest("StreamTcpReassembleRawTest03",
197  StreamTcpReassembleRawTest03);
198  UtRegisterTest("StreamTcpReassembleRawTest04",
199  StreamTcpReassembleRawTest04);
200  UtRegisterTest("StreamTcpReassembleRawTest05",
201  StreamTcpReassembleRawTest05);
202  UtRegisterTest("StreamTcpReassembleRawTest06",
203  StreamTcpReassembleRawTest06);
204  UtRegisterTest("StreamTcpReassembleRawTest07",
205  StreamTcpReassembleRawTest07);
206  UtRegisterTest("StreamTcpReassembleRawTest08",
207  StreamTcpReassembleRawTest08);
208 }
void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, uint64_t progress)
update stream engine after detection
#define RAWREASSEMBLY_STEP_WITH_PROGRESS(seq, seg, seglen, buf, buflen, lastack, progress)
int StreamReassembleRaw(TcpSession *ssn, const Packet *p, StreamReassembleRawFunc Callback, void *cb_data, uint64_t *progress_out, bool respect_inspect_depth)
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define RAWREASSEMBLY_START(isn)
void PrintRawDataFp(FILE *fp, const uint8_t *buf, uint32_t buflen)
Definition: util-print.c:141
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:269
#define RAWREASSEMBLY_STEP(seq, seg, seglen, buf, buflen)
#define RAWREASSEMBLY_END