1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
|
/* Copyright (C) 2007-2010 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Victor Julien <victor@inliniac.net>
*/
#ifndef __STREAM_TCP_PRIVATE_H__
#define __STREAM_TCP_PRIVATE_H__
#include "util-pool-thread.h"
#include "util-streaming-buffer.h"
#define STREAMTCP_QUEUE_FLAG_TS 0x01
#define STREAMTCP_QUEUE_FLAG_WS 0x02
#define STREAMTCP_QUEUE_FLAG_SACK 0x04
/** Tracking SYNs and SYN/ACKs */
typedef struct TcpStateQueue_ {
uint8_t flags;
uint8_t wscale;
uint16_t win;
uint32_t seq;
uint32_t ack;
uint32_t ts;
uint32_t pkt_ts;
struct TcpStateQueue_ *next;
} TcpStateQueue;
typedef struct StreamTcpSackRecord {
uint32_t le; /**< left edge, host order */
uint32_t re; /**< right edge, host order */
RB_ENTRY(StreamTcpSackRecord) rb;
} StreamTcpSackRecord;
int TcpSackCompare(struct StreamTcpSackRecord *a, struct StreamTcpSackRecord *b);
/* red-black tree prototype for SACK records */
RB_HEAD(TCPSACK, StreamTcpSackRecord);
RB_PROTOTYPE(TCPSACK, StreamTcpSackRecord, rb, TcpSackCompare);
#define TCPSEG_PKT_HDR_DEFAULT_SIZE 64
/*
* Struct to add the additional information required to use TcpSegments to dump
* a packet capture to file with the stream-pcap-log output option. This is only
* used if the session-dump option is enabled.
*/
typedef struct TcpSegmentPcapHdrStorage_ {
struct timeval ts;
uint32_t pktlen;
uint32_t alloclen;
uint8_t *pkt_hdr;
} TcpSegmentPcapHdrStorage;
typedef struct TcpSegment {
PoolThreadId pool_id;
uint16_t payload_len; /**< actual size of the payload */
uint32_t seq;
RB_ENTRY(TcpSegment) __attribute__((__packed__)) rb;
StreamingBufferSegment sbseg;
TcpSegmentPcapHdrStorage *pcap_hdr_storage;
} __attribute__((__packed__)) TcpSegment;
/** \brief compare function for the Segment tree
*
* Main sort point is the sequence number. When sequence numbers
* are equal compare payload_len as well. This way the tree is
* sorted by seq, and in case of duplicate seqs we are sorted
* small to large.
*/
int TcpSegmentCompare(struct TcpSegment *a, struct TcpSegment *b);
/* red-black tree prototype for TcpSegment */
RB_HEAD(TCPSEG, TcpSegment);
RB_PROTOTYPE(TCPSEG, TcpSegment, rb, TcpSegmentCompare);
#define TCP_SEG_LEN(seg) (seg)->payload_len
#define TCP_SEG_OFFSET(seg) (seg)->sbseg.stream_offset
#define SEG_SEQ_RIGHT_EDGE(seg) ((seg)->seq + TCP_SEG_LEN((seg)))
/* get right edge of sequence space of seen segments.
* Only use if STREAM_HAS_SEEN_DATA is true. */
#define STREAM_SEQ_RIGHT_EDGE(stream) (stream)->segs_right_edge
#define STREAM_RIGHT_EDGE(stream) (STREAM_BASE_OFFSET((stream)) + (STREAM_SEQ_RIGHT_EDGE((stream)) - (stream)->base_seq))
/* return true if we have seen data. */
#define STREAM_HAS_SEEN_DATA(stream) StreamingBufferHasData(&(stream)->sb)
typedef struct TcpStream_ {
uint16_t flags:12; /**< Flag specific to the stream e.g. Timestamp */
/* coccinelle: TcpStream:flags:STREAMTCP_STREAM_FLAG_ */
uint16_t wscale:4; /**< wscale setting in this direction, 4 bits as max val is 15 */
uint8_t os_policy; /**< target based OS policy used for reassembly and handling packets*/
uint8_t tcp_flags; /**< TCP flags seen */
uint32_t isn; /**< initial sequence number */
uint32_t next_seq; /**< next expected sequence number */
uint32_t last_ack; /**< last ack'd sequence number in this stream */
uint32_t next_win; /**< next max seq within window */
uint32_t window; /**< current window setting, after wscale is applied */
uint32_t last_ts; /**< Time stamp (TSVAL) of the last seen packet for this stream*/
uint32_t last_pkt_ts; /**< Time of last seen packet for this stream (needed for PAWS update)
This will be used to validate the last_ts, when connection has been idle for
longer time.(RFC 1323)*/
/* reassembly */
uint32_t base_seq; /**< seq where we are left with reassembly. Matches STREAM_BASE_OFFSET below.
*/
uint32_t app_progress_rel; /**< app-layer progress relative to STREAM_BASE_OFFSET */
uint32_t raw_progress_rel; /**< raw reassembly progress relative to STREAM_BASE_OFFSET */
uint32_t log_progress_rel; /**< streaming logger progress relative to STREAM_BASE_OFFSET */
uint32_t min_inspect_depth; /**< min inspect size set by the app layer, to make sure enough data
* remains available for inspection together with app layer buffers */
uint32_t data_required; /**< data required from STREAM_APP_PROGRESS before calling app-layer again */
StreamingBuffer sb;
struct TCPSEG seg_tree; /**< red black tree of TCP segments. Data is stored in TcpStream::sb */
uint32_t segs_right_edge;
uint32_t sack_size; /**< combined size of the SACK ranges currently in our tree. Updated
* at INSERT/REMOVE time. */
struct TCPSACK sack_tree; /**< red back tree of TCP SACK records. */
} TcpStream;
#define STREAM_BASE_OFFSET(stream) ((stream)->sb.region.stream_offset)
#define STREAM_APP_PROGRESS(stream) (STREAM_BASE_OFFSET((stream)) + (stream)->app_progress_rel)
#define STREAM_RAW_PROGRESS(stream) (STREAM_BASE_OFFSET((stream)) + (stream)->raw_progress_rel)
#define STREAM_LOG_PROGRESS(stream) (STREAM_BASE_OFFSET((stream)) + (stream)->log_progress_rel)
/* from /usr/include/netinet/tcp.h */
enum TcpState {
TCP_NONE = 0,
// TCP_LISTEN = 1,
TCP_SYN_SENT = 2,
TCP_SYN_RECV = 3,
TCP_ESTABLISHED = 4,
TCP_FIN_WAIT1 = 5,
TCP_FIN_WAIT2 = 6,
TCP_TIME_WAIT = 7,
TCP_LAST_ACK = 8,
TCP_CLOSE_WAIT = 9,
TCP_CLOSING = 10,
TCP_CLOSED = 11,
};
/*
* Per SESSION flags
*/
/** Flag for mid stream session */
#define STREAMTCP_FLAG_MIDSTREAM BIT_U32(0)
/** Flag for mid stream established session */
#define STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED BIT_U32(1)
/** Flag for mid session when syn/ack is received */
#define STREAMTCP_FLAG_MIDSTREAM_SYNACK BIT_U32(2)
/** Flag for TCP Timestamp option */
#define STREAMTCP_FLAG_TIMESTAMP BIT_U32(3)
/** Server supports wscale (even though it can be 0) */
#define STREAMTCP_FLAG_SERVER_WSCALE BIT_U32(4)
/** Closed by RST */
#define STREAMTCP_FLAG_CLOSED_BY_RST BIT_U32(5)
/** Flag to indicate that the session is handling asynchronous stream.*/
#define STREAMTCP_FLAG_ASYNC BIT_U32(6)
/** Flag to indicate we're dealing with 4WHS: SYN, SYN, SYN/ACK, ACK
* (http://www.breakingpointsystems.com/community/blog/tcp-portals-the-three-way-handshake-is-a-lie) */
#define STREAMTCP_FLAG_4WHS BIT_U32(7)
/** Flag to indicate that this session is possible trying to evade the detection
* (http://www.packetstan.com/2010/06/recently-ive-been-on-campaign-to-make.html) */
#define STREAMTCP_FLAG_DETECTION_EVASION_ATTEMPT BIT_U32(8)
/** Flag to indicate the client (SYN pkt) permits SACK */
#define STREAMTCP_FLAG_CLIENT_SACKOK BIT_U32(9)
/** Flag to indicate both sides of the session permit SACK (SYN + SYN/ACK) */
#define STREAMTCP_FLAG_SACKOK BIT_U32(10)
/** Session is in "lossy" state, be liberal */
#define STREAMTCP_FLAG_LOSSY_BE_LIBERAL BIT_U32(11)
/** 3WHS confirmed by server -- if suri sees 3whs ACK but server doesn't (pkt
* is lost on the way to server), SYN/ACK is retransmitted. If server sends
* normal packet we assume 3whs to be completed. Only used for SYN/ACK resend
* event. */
#define STREAMTCP_FLAG_3WHS_CONFIRMED BIT_U32(12)
/** App Layer tracking/reassembly is disabled */
#define STREAMTCP_FLAG_APP_LAYER_DISABLED BIT_U32(13)
/** Stream can be bypass */
#define STREAMTCP_FLAG_BYPASS BIT_U32(14)
/** SSN uses TCP Fast Open */
#define STREAMTCP_FLAG_TCP_FAST_OPEN BIT_U32(15)
/** SYN/ACK ignored the data while ACKing the SYN */
#define STREAMTCP_FLAG_TFO_DATA_IGNORED BIT_U32(16)
/* zero window probe */
#define STREAMTCP_FLAG_ZWP_TS BIT_U32(17)
#define STREAMTCP_FLAG_ZWP_TC BIT_U32(18)
/*
* Per STREAM flags
*/
/** Flag to indicate that we have seen gap on the stream */
#define STREAMTCP_STREAM_FLAG_HAS_GAP BIT_U16(0)
/** Flag to avoid stream reassembly/app layer inspection for the stream */
#define STREAMTCP_STREAM_FLAG_NOREASSEMBLY BIT_U16(1)
/** we received a keep alive */
#define STREAMTCP_STREAM_FLAG_KEEPALIVE BIT_U16(2)
/** Stream has reached it's reassembly depth, all further packets are ignored */
#define STREAMTCP_STREAM_FLAG_DEPTH_REACHED BIT_U16(3)
/** Trigger reassembly next time we need 'raw' */
#define STREAMTCP_STREAM_FLAG_TRIGGER_RAW BIT_U16(4)
/** Stream supports TIMESTAMP -- used to set ssn STREAMTCP_FLAG_TIMESTAMP
* flag. */
#define STREAMTCP_STREAM_FLAG_TIMESTAMP BIT_U16(5)
/** Flag to indicate the zero value of timestamp */
#define STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP BIT_U16(6)
/** App proto detection completed */
#define STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED BIT_U16(7)
/** App proto detection skipped */
#define STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED BIT_U16(8)
/** Raw reassembly disabled for new segments */
#define STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED BIT_U16(9)
/** Raw reassembly disabled completely */
#define STREAMTCP_STREAM_FLAG_DISABLE_RAW BIT_U16(10)
#define STREAMTCP_STREAM_FLAG_RST_RECV BIT_U16(11)
/** NOTE: flags field is 12 bits */
#define PAWS_24DAYS 2073600 /**< 24 days in seconds */
#define PKT_IS_IN_RIGHT_DIR(ssn, p) ((ssn)->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK ? \
PKT_IS_TOSERVER(p) ? (p)->flowflags &= ~FLOW_PKT_TOSERVER \
(p)->flowflags |= FLOW_PKT_TOCLIENT : (p)->flowflags &= ~FLOW_PKT_TOCLIENT \
(p)->flowflags |= FLOW_PKT_TOSERVER : 0)
/* Macro's for comparing Sequence numbers
* Page 810 from TCP/IP Illustrated, Volume 2. */
#define SEQ_EQ(a,b) ((int32_t)((a) - (b)) == 0)
#define SEQ_LT(a,b) ((int32_t)((a) - (b)) < 0)
#define SEQ_LEQ(a,b) ((int32_t)((a) - (b)) <= 0)
#define SEQ_GT(a,b) ((int32_t)((a) - (b)) > 0)
#define SEQ_GEQ(a,b) ((int32_t)((a) - (b)) >= 0)
#define SEQ_MIN(a, b) (SEQ_LT((a), (b)) ? (a) : (b))
#define SEQ_MAX(a, b) (SEQ_GT((a), (b)) ? (a) : (b))
#define STREAMTCP_SET_RA_BASE_SEQ(stream, seq) { \
do { \
(stream)->base_seq = (seq) + 1; \
} while(0); \
}
#define StreamTcpSetEvent(p, e) \
{ \
if ((p)->flags & PKT_STREAM_NO_EVENTS) { \
SCLogDebug("not setting event %d on pkt %p (%" PRIu64 "), " \
"stream in known bad condition", \
(e), p, (p)->pcap_cnt); \
} else { \
SCLogDebug("setting event %d on pkt %p (%" PRIu64 ")", (e), p, (p)->pcap_cnt); \
ENGINE_SET_EVENT((p), (e)); \
p->tcpvars.stream_pkt_flags |= STREAM_PKT_FLAG_EVENTSET; \
} \
}
typedef struct TcpSession_ {
PoolThreadId pool_id;
uint8_t state:4; /**< tcp state from state enum */
uint8_t pstate:4; /**< previous state */
uint8_t queue_len; /**< length of queue list below */
int8_t data_first_seen_dir;
/** track all the tcp flags we've seen */
uint8_t tcp_packet_flags;
/* coccinelle: TcpSession:flags:STREAMTCP_FLAG */
uint32_t flags;
uint32_t reassembly_depth; /**< reassembly depth for the stream */
TcpStream server;
TcpStream client;
TcpStateQueue *queue; /**< list of SYN/ACK candidates */
} TcpSession;
#define StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream) \
((stream)->flags |= STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)
#define StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream) \
((stream)->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)
#define StreamTcpResetStreamFlagAppProtoDetectionCompleted(stream) \
((stream)->flags &= ~STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED);
#define StreamTcpDisableAppLayerReassembly(ssn) do { \
SCLogDebug("setting STREAMTCP_FLAG_APP_LAYER_DISABLED on ssn %p", ssn); \
((ssn)->flags |= STREAMTCP_FLAG_APP_LAYER_DISABLED); \
} while (0);
#define STREAM_PKT_FLAG_RETRANSMISSION BIT_U16(0)
#define STREAM_PKT_FLAG_SPURIOUS_RETRANSMISSION BIT_U16(1)
#define STREAM_PKT_FLAG_STATE_UPDATE BIT_U16(2)
#define STREAM_PKT_FLAG_KEEPALIVE BIT_U16(3)
#define STREAM_PKT_FLAG_KEEPALIVEACK BIT_U16(4)
#define STREAM_PKT_FLAG_WINDOWUPDATE BIT_U16(5)
#define STREAM_PKT_FLAG_EVENTSET BIT_U16(6)
#define STREAM_PKT_FLAG_DUP_ACK BIT_U16(7)
#define STREAM_PKT_FLAG_DSACK BIT_U16(8)
#define STREAM_PKT_FLAG_ACK_UNSEEN_DATA BIT_U16(9)
#define STREAM_PKT_FLAG_TCP_PORT_REUSE BIT_U16(10)
#define STREAM_PKT_FLAG_TCP_ZERO_WIN_PROBE BIT_U16(11)
#define STREAM_PKT_FLAG_TCP_ZERO_WIN_PROBE_ACK BIT_U16(12)
#define STREAM_PKT_FLAG_SET(p, f) (p)->tcpvars.stream_pkt_flags |= (f)
#endif /* __STREAM_TCP_PRIVATE_H__ */
|