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