suricata
decode-tcp.h
Go to the documentation of this file.
1 /* Copyright (C) 2007-2022 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  * \todo RAW* macro's should be returning the raw value, not the host order
23  */
24 
25 #ifndef SURICATA_DECODE_TCP_H
26 #define SURICATA_DECODE_TCP_H
27 
28 #define TCP_HEADER_LEN 20
29 #define TCP_OPTLENMAX 40
30 #define TCP_OPTMAX 20 /* every opt is at least 2 bytes
31  * (type + len), except EOL and NOP */
32 
33 /* TCP flags */
34 
35 #define TH_FIN 0x01
36 #define TH_SYN 0x02
37 #define TH_RST 0x04
38 #define TH_PUSH 0x08
39 #define TH_ACK 0x10
40 #define TH_URG 0x20
41 /** Establish a new connection reducing window */
42 #define TH_ECN 0x40
43 /** Echo Congestion flag */
44 #define TH_CWR 0x80
45 
46 /* tcp option codes */
47 #define TCP_OPT_EOL 0x00
48 #define TCP_OPT_NOP 0x01
49 #define TCP_OPT_MSS 0x02
50 #define TCP_OPT_WS 0x03
51 #define TCP_OPT_SACKOK 0x04
52 #define TCP_OPT_SACK 0x05
53 #define TCP_OPT_TS 0x08
54 #define TCP_OPT_TFO 0x22 /* TCP Fast Open */
55 #define TCP_OPT_EXP1 0xfd /* Experimental, could be TFO */
56 #define TCP_OPT_EXP2 0xfe /* Experimental, could be TFO */
57 #define TCP_OPT_MD5 0x13 /* 19: RFC 2385 TCP MD5 option */
58 #define TCP_OPT_AO 0x1d /* 29: RFC 5925 TCP AO option */
59 
60 #define TCP_OPT_SACKOK_LEN 2
61 #define TCP_OPT_WS_LEN 3
62 #define TCP_OPT_TS_LEN 10
63 #define TCP_OPT_MSS_LEN 4
64 #define TCP_OPT_SACK_MIN_LEN 10 /* hdr 2, 1 pair 8 = 10 */
65 #define TCP_OPT_SACK_MAX_LEN 34 /* hdr 2, 4 pair 32= 34 */
66 #define TCP_OPT_TFO_MIN_LEN 4 /* kind, len, 2 bytes cookie: 4 */
67 #define TCP_OPT_TFO_MAX_LEN 18 /* kind, len, 18 */
68 
69 /** Max valid wscale value. */
70 #define TCP_WSCALE_MAX 14
71 
72 #define TCP_GET_RAW_OFFSET(tcph) (((tcph)->th_offx2 & 0xf0) >> 4)
73 #define TCP_GET_RAW_HLEN(tcph) ((uint8_t)(TCP_GET_RAW_OFFSET((tcph)) << 2))
74 #define TCP_GET_RAW_X2(tcph) (unsigned char)((tcph)->th_offx2 & 0x0f)
75 #define TCP_GET_RAW_SRC_PORT(tcph) SCNtohs((tcph)->th_sport)
76 #define TCP_GET_RAW_DST_PORT(tcph) SCNtohs((tcph)->th_dport)
77 
78 #define TCP_SET_RAW_TCP_OFFSET(tcph, value) ((tcph)->th_offx2 = (unsigned char)(((tcph)->th_offx2 & 0x0f) | (value << 4)))
79 #define TCP_SET_RAW_TCP_X2(tcph, value) ((tcph)->th_offx2 = (unsigned char)(((tcph)->th_offx2 & 0xf0) | (value & 0x0f)))
80 
81 #define TCP_GET_RAW_SEQ(tcph) SCNtohl((tcph)->th_seq)
82 #define TCP_GET_RAW_ACK(tcph) SCNtohl((tcph)->th_ack)
83 
84 #define TCP_GET_RAW_WINDOW(tcph) SCNtohs((tcph)->th_win)
85 #define TCP_GET_RAW_URG_POINTER(tcph) SCNtohs((tcph)->th_urp)
86 #define TCP_GET_RAW_SUM(tcph) SCNtohs((tcph)->th_sum)
87 
88 /** macro for getting the first timestamp from the packet in host order */
89 #define TCP_GET_TSVAL(p) ((p)->l4.vars.tcp.ts_val)
90 
91 /** macro for getting the second timestamp from the packet in host order. */
92 #define TCP_GET_TSECR(p) ((p)->l4.vars.tcp.ts_ecr)
93 
94 #define TCP_HAS_WSCALE(p) ((p)->l4.vars.tcp.wscale_set)
95 #define TCP_HAS_SACK(p) (p)->l4.vars.tcp.sack_set
96 #define TCP_HAS_TS(p) ((p)->l4.vars.tcp.ts_set)
97 #define TCP_HAS_MSS(p) ((p)->l4.vars.tcp.mss_set)
98 #define TCP_HAS_TFO(p) ((p)->l4.vars.tcp.tfo_set)
99 
100 /** macro for getting the wscale from the packet. */
101 #define TCP_GET_WSCALE(p) (p)->l4.vars.tcp.wscale
102 
103 #define TCP_GET_SACKOK(p) (p)->l4.vars.tcp.sack_ok
104 #define TCP_GET_SACK_PTR(p, tcph) ((uint8_t *)(tcph)) + (p)->l4.vars.tcp.sack_offset
105 #define TCP_GET_SACK_CNT(p) (p)->l4.vars.tcp.sack_cnt
106 #define TCP_GET_MSS(p) (p)->l4.vars.tcp.mss
107 
108 #define TCP_GET_OFFSET(p) TCP_GET_RAW_OFFSET((p)->tcph)
109 #define TCP_GET_X2(p) TCP_GET_RAW_X2((p)->tcph)
110 #define TCP_GET_HLEN(p) ((uint8_t)(TCP_GET_OFFSET((p)) << 2))
111 #define TCP_GET_SRC_PORT(p) TCP_GET_RAW_SRC_PORT((p)->tcph)
112 #define TCP_GET_DST_PORT(p) TCP_GET_RAW_DST_PORT((p)->tcph)
113 #define TCP_GET_SEQ(p) TCP_GET_RAW_SEQ((p)->tcph)
114 #define TCP_GET_ACK(p) TCP_GET_RAW_ACK((p)->tcph)
115 #define TCP_GET_WINDOW(p) TCP_GET_RAW_WINDOW((p)->tcph)
116 #define TCP_GET_URG_POINTER(p) TCP_GET_RAW_URG_POINTER((p)->tcph)
117 #define TCP_GET_SUM(p) TCP_GET_RAW_SUM((p)->tcph)
118 #define TCP_GET_FLAGS(p) (p)->tcph->th_flags
119 
120 #define TCP_ISSET_FLAG_RAW_FIN(p) ((tcph)->th_flags & TH_FIN)
121 #define TCP_ISSET_FLAG_RAW_SYN(p) ((tcph)->th_flags & TH_SYN)
122 #define TCP_ISSET_FLAG_RAW_RST(p) ((tcph)->th_flags & TH_RST)
123 #define TCP_ISSET_FLAG_RAW_PUSH(p) ((tcph)->th_flags & TH_PUSH)
124 #define TCP_ISSET_FLAG_RAW_ACK(p) ((tcph)->th_flags & TH_ACK)
125 #define TCP_ISSET_FLAG_RAW_URG(p) ((tcph)->th_flags & TH_URG)
126 #define TCP_ISSET_FLAG_RAW_RES2(p) ((tcph)->th_flags & TH_RES2)
127 #define TCP_ISSET_FLAG_RAW_RES1(p) ((tcph)->th_flags & TH_RES1)
128 
129 #define TCP_ISSET_FLAG_FIN(p) ((p)->tcph->th_flags & TH_FIN)
130 #define TCP_ISSET_FLAG_SYN(p) ((p)->tcph->th_flags & TH_SYN)
131 #define TCP_ISSET_FLAG_RST(p) ((p)->tcph->th_flags & TH_RST)
132 #define TCP_ISSET_FLAG_PUSH(p) ((p)->tcph->th_flags & TH_PUSH)
133 #define TCP_ISSET_FLAG_ACK(p) ((p)->tcph->th_flags & TH_ACK)
134 #define TCP_ISSET_FLAG_URG(p) ((p)->tcph->th_flags & TH_URG)
135 #define TCP_ISSET_FLAG_RES2(p) ((p)->tcph->th_flags & TH_RES2)
136 #define TCP_ISSET_FLAG_RES1(p) ((p)->tcph->th_flags & TH_RES1)
137 
138 typedef struct TCPOpt_ {
139  uint8_t type;
140  uint8_t len;
141  const uint8_t *data;
142 } TCPOpt;
143 
144 typedef struct TCPOptSackRecord_ {
145  uint32_t le; /**< left edge, network order */
146  uint32_t re; /**< right edge, network order */
148 
149 typedef struct TCPHdr_
150 {
151  uint16_t th_sport; /**< source port */
152  uint16_t th_dport; /**< destination port */
153  uint32_t th_seq; /**< sequence number */
154  uint32_t th_ack; /**< acknowledgement number */
155  uint8_t th_offx2; /**< offset and reserved */
156  uint8_t th_flags; /**< pkt flags */
157  uint16_t th_win; /**< pkt window */
158  uint16_t th_sum; /**< checksum */
159  uint16_t th_urp; /**< urgent pointer */
160 } TCPHdr;
161 
162 typedef struct TCPVars_
163 {
164  /* commonly used and needed opts */
165  uint8_t md5_option_present : 1;
166  uint8_t ao_option_present : 1;
167  uint8_t ts_set : 1;
168  uint8_t sack_ok : 1;
169  uint8_t mss_set : 1;
170  uint8_t tfo_set : 1;
171  uint8_t wscale_set : 1;
172  uint8_t sack_set : 1;
173  uint8_t wscale;
174  uint8_t sack_cnt; /**< number of sack records */
175  uint16_t mss; /**< MSS value in host byte order */
177  uint32_t ts_val; /* host-order */
178  uint32_t ts_ecr; /* host-order */
179  uint16_t sack_offset; /**< offset relative to tcp header start */
180 } TCPVars;
181 
182 void DecodeTCPRegisterTests(void);
183 
184 /** -------- Inline functions ------- */
185 
186 /**
187  * \brief Calculate or validate the checksum for the TCP packet
188  *
189  * \param shdr Pointer to source address field from the IP packet. Used as a
190  * part of the pseudoheader for computing the checksum
191  * \param pkt Pointer to the start of the TCP packet
192  * \param tlen Total length of the TCP packet(header + payload)
193  * \param init The current checksum if validating, 0 if generating.
194  *
195  * \retval csum For validation 0 will be returned for success, for calculation
196  * this will be the checksum.
197  */
198 static inline uint16_t TCPChecksum(
199  const uint16_t *shdr, const uint16_t *pkt, uint16_t tlen, uint16_t init)
200 {
201  uint16_t pad = 0;
202  uint32_t csum = init;
203 
204  csum += shdr[0] + shdr[1] + shdr[2] + shdr[3] + htons(6) + htons(tlen);
205 
206  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
207  pkt[7] + pkt[9];
208 
209  tlen -= 20;
210  pkt += 10;
211 
212  while (tlen >= 32) {
213  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
214  pkt[7] +
215  pkt[8] +
216  pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] +
217  pkt[14] + pkt[15];
218  tlen -= 32;
219  pkt += 16;
220  }
221 
222  while(tlen >= 8) {
223  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3];
224  tlen -= 8;
225  pkt += 4;
226  }
227 
228  while(tlen >= 4) {
229  csum += pkt[0] + pkt[1];
230  tlen -= 4;
231  pkt += 2;
232  }
233 
234  while (tlen > 1) {
235  csum += pkt[0];
236  pkt += 1;
237  tlen -= 2;
238  }
239 
240  if (tlen == 1) {
241  *(uint8_t *)(&pad) = (*(uint8_t *)pkt);
242  csum += pad;
243  }
244 
245  csum = (csum >> 16) + (csum & 0x0000FFFF);
246  csum += (csum >> 16);
247 
248  return (uint16_t)~csum;
249 }
250 
251 /**
252  * \brief Calculate or validate the checksum for the TCP packet
253  *
254  * \param shdr Pointer to source address field from the IPV6 packet. Used as a
255  * part of the psuedoheader for computing the checksum
256  * \param pkt Pointer to the start of the TCP packet
257  * \param tlen Total length of the TCP packet(header + payload)
258  * \param init The current checksum if validating, 0 if generating.
259  *
260  * \retval csum For validation 0 will be returned for success, for calculation
261  * this will be the checksum.
262  */
263 static inline uint16_t TCPV6Checksum(
264  const uint16_t *shdr, const uint16_t *pkt, uint16_t tlen, uint16_t init)
265 {
266  uint16_t pad = 0;
267  uint32_t csum = init;
268 
269  csum += shdr[0] + shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] +
270  shdr[6] + shdr[7] + shdr[8] + shdr[9] + shdr[10] + shdr[11] +
271  shdr[12] + shdr[13] + shdr[14] + shdr[15] + htons(6) + htons(tlen);
272 
273  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
274  pkt[7] + pkt[9];
275 
276  tlen -= 20;
277  pkt += 10;
278 
279  while (tlen >= 32) {
280  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
281  pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] +
282  pkt[14] + pkt[15];
283  tlen -= 32;
284  pkt += 16;
285  }
286 
287  while(tlen >= 8) {
288  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3];
289  tlen -= 8;
290  pkt += 4;
291  }
292 
293  while(tlen >= 4) {
294  csum += pkt[0] + pkt[1];
295  tlen -= 4;
296  pkt += 2;
297  }
298 
299  while (tlen > 1) {
300  csum += pkt[0];
301  pkt += 1;
302  tlen -= 2;
303  }
304 
305  if (tlen == 1) {
306  *(uint8_t *)(&pad) = (*(uint8_t *)pkt);
307  csum += pad;
308  }
309 
310  csum = (csum >> 16) + (csum & 0x0000FFFF);
311  csum += (csum >> 16);
312 
313  return (uint16_t)~csum;
314 }
315 
316 #endif /* SURICATA_DECODE_TCP_H */
TCPVars
struct TCPVars_ TCPVars
TCPVars_::ao_option_present
uint8_t ao_option_present
Definition: decode-tcp.h:165
TCPOpt_
Definition: decode-tcp.h:137
TCPHdr_::th_dport
uint16_t th_dport
Definition: decode-tcp.h:151
TCPVars_::mss_set
uint8_t mss_set
Definition: decode-tcp.h:168
TCPVars_::ts_set
uint8_t ts_set
Definition: decode-tcp.h:166
TCPVars_
Definition: decode-tcp.h:162
DecodeTCPRegisterTests
void DecodeTCPRegisterTests(void)
Definition: decode-tcp.c:532
TCPHdr_::th_win
uint16_t th_win
Definition: decode-tcp.h:156
TCPVars_::sack_ok
uint8_t sack_ok
Definition: decode-tcp.h:167
TCPOpt_::data
const uint8_t * data
Definition: decode-tcp.h:140
pad
uint16_t pad
Definition: source-erf-file.c:61
TCPHdr_::th_ack
uint32_t th_ack
Definition: decode-tcp.h:153
TCPHdr_::th_sport
uint16_t th_sport
Definition: decode-tcp.h:150
TCPHdr_::th_flags
uint8_t th_flags
Definition: decode-tcp.h:155
TCPVars_::ts_ecr
uint32_t ts_ecr
Definition: decode-tcp.h:177
TCPOpt_::type
uint8_t type
Definition: decode-tcp.h:138
TCPHdr_::th_seq
uint32_t th_seq
Definition: decode-tcp.h:152
TCPVars_::sack_offset
uint16_t sack_offset
Definition: decode-tcp.h:178
TCPHdr_::th_offx2
uint8_t th_offx2
Definition: decode-tcp.h:154
TCPHdr_::th_sum
uint16_t th_sum
Definition: decode-tcp.h:157
TCPOpt
struct TCPOpt_ TCPOpt
TCPHdr_::th_urp
uint16_t th_urp
Definition: decode-tcp.h:158
TCPVars_::stream_pkt_flags
uint16_t stream_pkt_flags
Definition: decode-tcp.h:175
TCPOpt_::len
uint8_t len
Definition: decode-tcp.h:139
TCPOptSackRecord_
Definition: decode-tcp.h:143
TCPVars_::tfo_set
uint8_t tfo_set
Definition: decode-tcp.h:169
TCPVars_::wscale
uint8_t wscale
Definition: decode-tcp.h:172
TCPVars_::ts_val
uint32_t ts_val
Definition: decode-tcp.h:176
TCPOptSackRecord_::le
uint32_t le
Definition: decode-tcp.h:144
TCPVars_::md5_option_present
uint8_t md5_option_present
Definition: decode-tcp.h:164
TCPOptSackRecord_::re
uint32_t re
Definition: decode-tcp.h:145
TCPOptSackRecord
struct TCPOptSackRecord_ TCPOptSackRecord
TCPVars_::sack_cnt
uint8_t sack_cnt
Definition: decode-tcp.h:173
TCPHdr
struct TCPHdr_ TCPHdr
TCPHdr_
Definition: decode-tcp.h:149
TCPVars_::sack_set
uint8_t sack_set
Definition: decode-tcp.h:171
TCPVars_::mss
uint16_t mss
Definition: decode-tcp.h:174
TCPVars_::wscale_set
uint8_t wscale_set
Definition: decode-tcp.h:170