1 /* Copyright (C) 2007-2011 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 Victor Julien <victor@inliniac.net>
22 *
23 * Helper functions for the stream engine.
24 */
25
26 #include "suricata-common.h"
27
28 #include "stream-tcp-reassemble.h"
29 #include "stream-tcp-inline.h"
30 #include "stream-tcp.h"
31 #include "stream-tcp-util.h"
32
33 #include "util-memcmp.h"
34 #include "util-print.h"
35
36 #include "util-unittest.h"
37 #include "util-unittest-helper.h"
38 #include "ippair.h"
39
40 #ifdef UNITTESTS
41
42 /* unittest helper functions */
43
StreamTcpUTInit(TcpReassemblyThreadCtx ** ra_ctx)44 void StreamTcpUTInit(TcpReassemblyThreadCtx **ra_ctx)
45 {
46 StreamTcpInitConfig(TRUE);
47 IPPairInitConfig(TRUE);
48 *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
49 }
50
StreamTcpUTDeinit(TcpReassemblyThreadCtx * ra_ctx)51 void StreamTcpUTDeinit(TcpReassemblyThreadCtx *ra_ctx)
52 {
53 StreamTcpReassembleFreeThreadCtx(ra_ctx);
54 StreamTcpFreeConfig(TRUE);
55 stream_config.flags &= ~STREAMTCP_INIT_FLAG_INLINE;
56 }
57
StreamTcpUTInitInline(void)58 void StreamTcpUTInitInline(void) {
59 stream_config.flags |= STREAMTCP_INIT_FLAG_INLINE;
60 }
61
StreamTcpUTSetupSession(TcpSession * ssn)62 void StreamTcpUTSetupSession(TcpSession *ssn)
63 {
64 memset(ssn, 0x00, sizeof(TcpSession));
65
66 StreamingBuffer x = STREAMING_BUFFER_INITIALIZER(&stream_config.sbcnf);
67 ssn->client.sb = x;
68 ssn->server.sb = x;
69 }
70
StreamTcpUTClearSession(TcpSession * ssn)71 void StreamTcpUTClearSession(TcpSession *ssn)
72 {
73 StreamTcpUTClearStream(&ssn->client);
74 StreamTcpUTClearStream(&ssn->server);
75 StreamTcpSessionCleanup(ssn);
76 memset(ssn, 0x00, sizeof(TcpSession));
77 }
78
StreamTcpUTSetupStream(TcpStream * s,uint32_t isn)79 void StreamTcpUTSetupStream(TcpStream *s, uint32_t isn)
80 {
81 memset(s, 0x00, sizeof(TcpStream));
82
83 s->isn = isn;
84 STREAMTCP_SET_RA_BASE_SEQ(s, isn);
85 s->base_seq = isn+1;
86
87 StreamingBuffer x = STREAMING_BUFFER_INITIALIZER(&stream_config.sbcnf);
88 s->sb = x;
89 }
90
StreamTcpUTClearStream(TcpStream * s)91 void StreamTcpUTClearStream(TcpStream *s)
92 {
93 StreamTcpStreamCleanup(s);
94 }
95
96 /** \brief wrapper for StreamTcpReassembleHandleSegmentHandleData */
StreamTcpUTAddPayload(ThreadVars * tv,TcpReassemblyThreadCtx * ra_ctx,TcpSession * ssn,TcpStream * stream,uint32_t seq,uint8_t * payload,uint16_t len)97 int StreamTcpUTAddPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, uint32_t seq, uint8_t *payload, uint16_t len)
98 {
99 Packet *p = UTHBuildPacketReal(payload, len, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
100 if (p == NULL) {
101 return -1;
102 }
103 p->tcph->th_seq = htonl(seq);
104 p->tcph->th_ack = htonl(31);
105
106 if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) < 0)
107 return -1;
108
109 UTHFreePacket(p);
110 return 0;
111 }
112
StreamTcpUTAddSegmentWithPayload(ThreadVars * tv,TcpReassemblyThreadCtx * ra_ctx,TcpStream * stream,uint32_t seq,uint8_t * payload,uint16_t len)113 int StreamTcpUTAddSegmentWithPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, uint32_t seq, uint8_t *payload, uint16_t len)
114 {
115 TcpSegment *s = StreamTcpGetSegment(tv, ra_ctx);
116 if (s == NULL) {
117 return -1;
118 }
119
120 s->seq = seq;
121 TCP_SEG_LEN(s) = len;
122
123 Packet *p = UTHBuildPacketReal(payload, len, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
124 if (p == NULL) {
125 return -1;
126 }
127 p->tcph->th_seq = htonl(seq);
128
129 if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, s, p, TCP_GET_SEQ(p), p->payload, p->payload_len) < 0)
130 return -1;
131
132 UTHFreePacket(p);
133 return 0;
134 }
135
StreamTcpUTAddSegmentWithByte(ThreadVars * tv,TcpReassemblyThreadCtx * ra_ctx,TcpStream * stream,uint32_t seq,uint8_t byte,uint16_t len)136 int StreamTcpUTAddSegmentWithByte(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, uint32_t seq, uint8_t byte, uint16_t len)
137 {
138 TcpSegment *s = StreamTcpGetSegment(tv, ra_ctx);
139 if (s == NULL) {
140 return -1;
141 }
142
143 s->seq = seq;
144 TCP_SEG_LEN(s) = len;
145 uint8_t buf[len];
146 memset(buf, byte, len);
147
148 Packet *p = UTHBuildPacketReal(buf, len, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
149 if (p == NULL) {
150 return -1;
151 }
152 p->tcph->th_seq = htonl(seq);
153
154 if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, s, p, TCP_GET_SEQ(p), p->payload, p->payload_len) < 0)
155 return -1;
156 UTHFreePacket(p);
157 return 0;
158 }
159
160 /* tests */
161
StreamTcpUtilTest01(void)162 static int StreamTcpUtilTest01(void)
163 {
164 int ret = 0;
165 TcpReassemblyThreadCtx *ra_ctx = NULL;
166
167 StreamTcpUTInit(&ra_ctx);
168
169 if (ra_ctx == NULL) {
170 printf("ra_ctx is NULL: ");
171 goto end;
172 }
173
174 ret = 1;
175 end:
176 StreamTcpUTDeinit(ra_ctx);
177 return ret;
178 }
179
180
StreamTcpUtilStreamTest01(void)181 static int StreamTcpUtilStreamTest01(void)
182 {
183 TcpReassemblyThreadCtx *ra_ctx = NULL;
184 TcpStream stream;
185 ThreadVars tv;
186 memset(&tv, 0x00, sizeof(tv));
187
188 StreamTcpUTInit(&ra_ctx);
189 StreamTcpUTSetupStream(&stream, 1);
190
191 FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 2, 'A', 5) == -1);
192 FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 7, 'B', 5) == -1);
193 FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 12, 'C', 5) == -1);
194
195 TcpSegment *seg = RB_MIN(TCPSEG, &stream.seg_tree);
196 FAIL_IF_NULL(seg);
197 FAIL_IF(seg->seq != 2);
198
199 seg = TCPSEG_RB_NEXT(seg);
200 FAIL_IF_NULL(seg);
201 FAIL_IF(seg->seq != 7);
202
203 seg = TCPSEG_RB_NEXT(seg);
204 FAIL_IF_NULL(seg);
205 FAIL_IF(seg->seq != 12);
206
207 StreamTcpUTClearStream(&stream);
208 StreamTcpUTDeinit(ra_ctx);
209 PASS;
210 }
211
StreamTcpUtilStreamTest02(void)212 static int StreamTcpUtilStreamTest02(void)
213 {
214 TcpReassemblyThreadCtx *ra_ctx = NULL;
215 TcpStream stream;
216 ThreadVars tv;
217 memset(&tv, 0x00, sizeof(tv));
218
219 StreamTcpUTInit(&ra_ctx);
220 StreamTcpUTSetupStream(&stream, 1);
221
222 FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 7, 'B', 5) == -1);
223 FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 12, 'C', 5) == -1);
224 FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 2, 'A', 5) == -1);
225
226 TcpSegment *seg = RB_MIN(TCPSEG, &stream.seg_tree);
227 FAIL_IF_NULL(seg);
228 FAIL_IF(seg->seq != 2);
229
230 seg = TCPSEG_RB_NEXT(seg);
231 FAIL_IF_NULL(seg);
232 FAIL_IF(seg->seq != 7);
233
234 seg = TCPSEG_RB_NEXT(seg);
235 FAIL_IF_NULL(seg);
236 FAIL_IF(seg->seq != 12);
237
238 StreamTcpUTClearStream(&stream);
239 StreamTcpUTDeinit(ra_ctx);
240 PASS;
241 }
242
243 #endif
244
StreamTcpUtilRegisterTests(void)245 void StreamTcpUtilRegisterTests(void)
246 {
247 #ifdef UNITTESTS
248 UtRegisterTest("StreamTcpUtilTest01", StreamTcpUtilTest01);
249 UtRegisterTest("StreamTcpUtilStreamTest01", StreamTcpUtilStreamTest01);
250 UtRegisterTest("StreamTcpUtilStreamTest02", StreamTcpUtilStreamTest02);
251 #endif /* UNITTESTS */
252 }
253
254