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