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