suricata
stream-tcp-inline.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2016 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  * Functions for the "inline mode" of the stream engine.
24  */
25 
26 #include "suricata-common.h"
27 #include "decode.h"
28 #include "stream-tcp-private.h"
29 #include "stream-tcp-inline.h"
30 
31 #include "util-memcmp.h"
32 #include "util-print.h"
33 
34 #include "util-validate.h"
35 #include "util-unittest-helper.h"
36 
37 /**
38  * \brief Compare the shared data portion of two segments
39  *
40  * If no data is shared, 0 will be returned.
41  *
42  * \param seg1 first segment
43  * \param seg2 second segment
44  *
45  * \retval 0 shared data is the same (or no data is shared)
46  * \retval 1 shared data is different
47  */
49  const Packet *p, const TcpSegment *seg)
50 {
51  SCEnter();
52 
53  if (p == NULL || seg == NULL) {
54  SCReturnInt(0);
55  }
56 
57  DEBUG_VALIDATE_BUG_ON(SEQ_LEQ(seg->seq + TCP_SEG_LEN(seg), stream->base_seq));
58 
59  const uint8_t *seg_data;
60  uint32_t seg_datalen;
61  StreamingBufferSegmentGetData(&stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
62  if (seg_data == NULL || seg_datalen == 0)
63  SCReturnInt(0);
64 
65  const TCPHdr *tcph = PacketGetTCP(p);
66  const uint32_t pkt_seq = TCP_GET_RAW_SEQ(tcph);
67 
68  if (SEQ_EQ(pkt_seq, seg->seq) && p->payload_len == seg_datalen) {
69  int r = SCMemcmp(p->payload, seg_data, seg_datalen);
70  SCReturnInt(r);
71  } else if (SEQ_GT(pkt_seq, (seg->seq + seg_datalen))) {
72  SCReturnInt(0);
73  } else if (SEQ_GT(seg->seq, (pkt_seq + p->payload_len))) {
74  SCReturnInt(0);
75  } else {
76  SCLogDebug("p %u (%u), seg2 %u (%u)", pkt_seq,
77  p->payload_len, seg->seq, seg_datalen);
78 
79  uint32_t seg_seq = seg->seq;
80  if (SEQ_LT(seg_seq, stream->base_seq)) {
81  seg_seq = stream->base_seq;
82  }
83  uint32_t pkt_end = pkt_seq + p->payload_len;
84  uint32_t seg_end = seg_seq + seg_datalen;
85  SCLogDebug("pkt_end %u, seg_end %u", pkt_end, seg_end);
86 
87  /* get the minimal seg*_end */
88  uint32_t end = SEQ_MIN(seg_end, pkt_end);
89  /* and the max seq */
90  uint32_t seq = SEQ_MAX(pkt_seq, seg_seq);
91  seq = SEQ_MAX(seq, stream->base_seq);
92  SCLogDebug("seq %u, end %u", seq, end);
93 
94  uint32_t pkt_off = seq - pkt_seq;
95  uint32_t seg_off = seq - seg_seq;
96  SCLogDebug("pkt_off %u, seg_off %u", pkt_off, seg_off);
97 
98  uint32_t range = end - seq;
99  SCLogDebug("range %u", range);
100  DEBUG_VALIDATE_BUG_ON(range > 65536);
101 
102  if (range) {
103  int r = SCMemcmp(p->payload + pkt_off, seg_data + seg_off, range);
104  SCReturnInt(r);
105  }
106  SCReturnInt(0);
107  }
108 }
109 
110 /**
111  * \brief Replace (part of) the payload portion of a packet by the data
112  * in a TCP segment
113  *
114  * \param p Packet
115  * \param seg TCP segment
116  *
117  * \todo What about reassembled fragments?
118  * \todo What about unwrapped tunnel packets?
119  */
121  Packet *p, const TcpSegment *seg)
122 {
123  SCEnter();
124 
125  const TCPHdr *tcph = PacketGetTCP(p);
126  const uint32_t pseq = TCP_GET_RAW_SEQ(tcph);
127  uint32_t tseq = seg->seq;
128 
129  /* check if segment is within the packet */
130  if (tseq + TCP_SEG_LEN(seg) < pseq) {
131  SCReturn;
132  } else if (pseq + p->payload_len < tseq) {
133  SCReturn;
134  }
135 
136  const uint8_t *seg_data;
137  uint32_t seg_datalen;
138  StreamingBufferSegmentGetData(&stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
139 
140  uint32_t pend = pseq + p->payload_len;
141  uint32_t tend = tseq + seg_datalen;
142  SCLogDebug("pend %u, tend %u", pend, tend);
143 
144  /* get the minimal seg*_end */
145  uint32_t end = (SEQ_GT(pend, tend)) ? tend : pend;
146  /* and the max seq */
147  uint32_t seq = (SEQ_LT(pseq, tseq)) ? tseq : pseq;
148  SCLogDebug("seq %u, end %u", seq, end);
149 
150  uint32_t poff = seq - pseq;
151  uint32_t toff = seq - tseq;
152  SCLogDebug("poff %u, toff %u", poff, toff);
153 
154  uint32_t range = end - seq;
155  SCLogDebug("range %u", range);
156  DEBUG_VALIDATE_BUG_ON(range > 65536);
157 
158  if (range) {
159  /* update the packets payload. As payload is a ptr to either
160  * p->pkt or p->ext_pkt that is updated as well */
161  memcpy(p->payload+poff, seg_data+toff, range);
162 
163  /* flag as modified so we can reinject / replace after
164  * recalculating the checksum */
166  }
167 }
168 
169 #ifdef UNITTESTS
170 #include "tests/stream-tcp-inline.c"
171 #endif
TCP_GET_RAW_SEQ
#define TCP_GET_RAW_SEQ(tcph)
Definition: decode-tcp.h:80
TcpStream_
Definition: stream-tcp-private.h:106
TCP_SEG_LEN
#define TCP_SEG_LEN(seg)
Definition: stream-tcp-private.h:94
stream-tcp-inline.h
PKT_STREAM_MODIFIED
#define PKT_STREAM_MODIFIED
Definition: decode.h:1316
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
seq
uint32_t seq
Definition: stream-tcp-private.h:2
Packet_::payload
uint8_t * payload
Definition: decode.h:620
Packet_::flags
uint32_t flags
Definition: decode.h:562
TcpSegment::sbseg
StreamingBufferSegment sbseg
Definition: stream-tcp-private.h:77
StreamTcpInlineSegmentReplacePacket
void StreamTcpInlineSegmentReplacePacket(const TcpStream *stream, Packet *p, const TcpSegment *seg)
Replace (part of) the payload portion of a packet by the data in a TCP segment.
Definition: stream-tcp-inline.c:120
TcpSegment::seq
uint32_t seq
Definition: stream-tcp-private.h:75
p
Packet * p
Definition: fuzz_dataset.c:30
Packet_::payload_len
uint16_t payload_len
Definition: decode.h:621
util-unittest-helper.h
util-memcmp.h
decode.h
util-print.h
SCEnter
#define SCEnter(...)
Definition: util-debug.h:284
SCReturn
#define SCReturn
Definition: util-debug.h:286
TcpSegment
Definition: stream-tcp-private.h:72
Packet_
Definition: decode.h:516
stream-tcp-private.h
SEQ_MIN
#define SEQ_MIN(a, b)
Definition: stream-tcp-private.h:261
suricata-common.h
SEQ_GT
#define SEQ_GT(a, b)
Definition: stream-tcp-private.h:259
TcpStream_::base_seq
uint32_t base_seq
Definition: stream-tcp-private.h:124
TcpStream_::sb
StreamingBuffer sb
Definition: stream-tcp-private.h:135
SEQ_MAX
#define SEQ_MAX(a, b)
Definition: stream-tcp-private.h:262
util-validate.h
StreamTcpInlineSegmentCompare
int StreamTcpInlineSegmentCompare(const TcpStream *stream, const Packet *p, const TcpSegment *seg)
Compare the shared data portion of two segments.
Definition: stream-tcp-inline.c:48
SEQ_LT
#define SEQ_LT(a, b)
Definition: stream-tcp-private.h:257
SEQ_EQ
#define SEQ_EQ(a, b)
Definition: stream-tcp-private.h:256
SEQ_LEQ
#define SEQ_LEQ(a, b)
Definition: stream-tcp-private.h:258
StreamingBufferSegmentGetData
void StreamingBufferSegmentGetData(const StreamingBuffer *sb, const StreamingBufferSegment *seg, const uint8_t **data, uint32_t *data_len)
Definition: util-streaming-buffer.c:1760
stream-tcp-inline.c
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:288
SCMemcmp
#define SCMemcmp(a, b, c)
Definition: util-memcmp.h:289
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:109
TCPHdr_
Definition: decode-tcp.h:149