mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
313 lines
14 KiB
C
313 lines
14 KiB
C
/* 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 reassebly. 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)
|
|
|
|
/*
|
|
* 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 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_SET(p, f) (p)->tcpvars.stream_pkt_flags |= (f)
|
|
|
|
#endif /* __STREAM_TCP_PRIVATE_H__ */
|