1 //--------------------------------------------------------------------------
2 // Copyright (C) 2015-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
18
19 // tcp_normalization.cc author davis mcpherson <davmcphe@cisco.com>
20 // Created on: Jul 31, 2015
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "tcp_normalizer.h"
27
28 #include "tcp_module.h"
29 #include "tcp_stream_session.h"
30 #include "tcp_stream_tracker.h"
31
32 using namespace snort;
33
34 THREAD_LOCAL PegCount tcp_norm_stats[PC_TCP_MAX][NORM_MODE_MAX];
35
36 static const PegInfo pegName[] =
37 {
38 { CountType::SUM, "tcp_trim_syn", "tcp segments trimmed on SYN" },
39 { CountType::SUM, "tcp_trim_rst", "RST packets with data trimmed" },
40 { CountType::SUM, "tcp_trim_win", "data trimmed to window" },
41 { CountType::SUM, "tcp_trim_mss", "data trimmed to MSS" },
42 { CountType::SUM, "tcp_ecn_session", "ECN bits cleared" },
43 { CountType::SUM, "tcp_ts_nop", "timestamp options cleared" },
44 { CountType::SUM, "tcp_ips_data", "normalized segments" },
45 { CountType::SUM, "tcp_block", "blocked segments" },
46 { CountType::END, nullptr, nullptr }
47 };
48
get_normalization_pegs()49 const PegInfo* TcpNormalizer::get_normalization_pegs()
50 {
51 return pegName;
52 }
53
get_normalization_counts(unsigned & c)54 NormPegs TcpNormalizer::get_normalization_counts(unsigned& c)
55 {
56 c = PC_TCP_MAX;
57 return tcp_norm_stats;
58 }
59
trim_payload(TcpNormalizerState &,TcpSegmentDescriptor & tsd,uint32_t max,NormMode mode,TcpPegCounts peg,bool force)60 bool TcpNormalizer::trim_payload(TcpNormalizerState&, TcpSegmentDescriptor& tsd, uint32_t max,
61 NormMode mode, TcpPegCounts peg, bool force)
62 {
63 if ( force )
64 mode = NORM_MODE_ON;
65
66 tcp_norm_stats[peg][mode]++;
67
68 if ( mode == NORM_MODE_ON )
69 {
70 uint16_t fat = tsd.get_len() - max;
71 tsd.set_len(max);
72 tsd.set_packet_flags(PKT_RESIZED);
73 tsd.set_end_seq(tsd.get_end_seq() - fat);
74 return true;
75 }
76 return false;
77 }
78
strip_tcp_timestamp(TcpNormalizerState &,TcpSegmentDescriptor & tsd,const tcp::TcpOption * opt,NormMode mode)79 bool TcpNormalizer::strip_tcp_timestamp(
80 TcpNormalizerState&, TcpSegmentDescriptor& tsd, const tcp::TcpOption* opt, NormMode mode)
81 {
82 tcp_norm_stats[PC_TCP_TS_NOP][mode]++;
83
84 if (mode == NORM_MODE_ON)
85 {
86 // set raw option bytes to nops
87 memset((void*)opt, (uint32_t)tcp::TcpOptCode::NOP, tcp::TCPOLEN_TIMESTAMP);
88 tsd.set_packet_flags(PKT_MODIFIED);
89 return true;
90 }
91
92 return false;
93 }
94
packet_dropper(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd,NormFlags f)95 bool TcpNormalizer::packet_dropper(
96 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, NormFlags f)
97 {
98 if ( tsd.is_meta_ack_packet() )
99 return false;
100
101 const int8_t mode = (f == NORM_TCP_BLOCK) ? tns.tcp_block : tns.opt_block;
102
103 tcp_norm_stats[PC_TCP_BLOCK][mode]++;
104
105 if (mode == NORM_MODE_ON)
106 {
107 tsd.drop_packet();
108 tcpStats.discards++;
109 return true;
110 }
111
112 tcpStats.discards_skipped++;
113 return false;
114 }
115
trim_syn_payload(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd,uint32_t max)116 bool TcpNormalizer::trim_syn_payload(
117 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, uint32_t max)
118 {
119 if (tsd.get_len() > max)
120 return trim_payload(tns, tsd, max, (NormMode)tns.trim_syn, PC_TCP_TRIM_SYN);
121 return false;
122 }
123
trim_rst_payload(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd,uint32_t max)124 void TcpNormalizer::trim_rst_payload(
125 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, uint32_t max)
126 {
127 if (tsd.get_len() > max)
128 trim_payload(tns, tsd, max, (NormMode)tns.trim_rst, PC_TCP_TRIM_RST);
129 }
130
trim_win_payload(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd,uint32_t max,bool force)131 void TcpNormalizer::trim_win_payload(
132 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, uint32_t max, bool force)
133 {
134 if (tsd.get_len() > max)
135 trim_payload(tns, tsd, max, (NormMode)tns.trim_win, PC_TCP_TRIM_WIN, force);
136 }
137
trim_mss_payload(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd,uint32_t max)138 void TcpNormalizer::trim_mss_payload(
139 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, uint32_t max)
140 {
141 if (tsd.get_len() > max)
142 trim_payload(tns, tsd, max, (NormMode)tns.trim_mss, PC_TCP_TRIM_MSS);
143 }
144
ecn_tracker(TcpNormalizerState & tns,const tcp::TCPHdr * tcph,bool req3way)145 void TcpNormalizer::ecn_tracker(
146 TcpNormalizerState& tns, const tcp::TCPHdr* tcph, bool req3way)
147 {
148 if ( tcph->is_syn_ack() )
149 {
150 if ( !req3way || tns.session->ecn )
151 tns.session->ecn = ((tcph->th_flags & (TH_ECE | TH_CWR)) == TH_ECE);
152 }
153 else if ( tcph->is_syn() )
154 tns.session->ecn = tcph->are_flags_set(TH_ECE | TH_CWR);
155 }
156
ecn_stripper(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd)157 void TcpNormalizer::ecn_stripper(
158 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
159 {
160 const tcp::TCPHdr* tcph = tsd.get_tcph();
161 if (!tns.session->ecn && (tcph->th_flags & (TH_ECE | TH_CWR)))
162 {
163 if (tns.strip_ecn == NORM_MODE_ON)
164 {
165 (const_cast<tcp::TCPHdr*>(tcph))->th_flags &= ~(TH_ECE | TH_CWR);
166 tsd.set_packet_flags(PKT_MODIFIED);
167 }
168
169 tcp_norm_stats[PC_TCP_ECN_SSN][tns.strip_ecn]++;
170 }
171 }
172
173 // don't use the window if we may have missed scaling
174 // one way zero window is uninitialized
175 // two way zero window is actually closed (regardless of scaling)
get_stream_window(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd)176 uint32_t TcpNormalizer::get_stream_window(
177 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
178 {
179 int32_t window;
180
181 if ( tns.tracker->get_snd_wnd() )
182 {
183 if ( !(tns.session->flow->session_state & STREAM_STATE_MIDSTREAM ) )
184 return tns.tracker->get_snd_wnd();
185 }
186 else if ( tns.session->flow->two_way_traffic() )
187 return tns.tracker->get_snd_wnd();
188
189 // ensure the data is in the window
190 window = tsd.get_end_seq() - tns.tracker->r_win_base;
191 if ( window < 0 )
192 window = 0;
193
194 return (uint32_t)window;
195 }
196
get_tcp_timestamp(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd,bool strip)197 uint32_t TcpNormalizer::get_tcp_timestamp(
198 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd, bool strip)
199 {
200 if ( tsd.is_meta_ack_packet() )
201 return TF_NONE;
202
203 if ( tsd.get_pkt()->ptrs.decode_flags & DECODE_TCP_TS )
204 {
205 tcp::TcpOptIterator iter(tsd.get_tcph(), tsd.get_pkt() );
206
207 // using const because non-const is not supported
208 for ( const tcp::TcpOption& opt : iter )
209 {
210 if ( opt.code == tcp::TcpOptCode::TIMESTAMP )
211 {
212 bool stripped = false;
213
214 if (strip)
215 stripped = strip_tcp_timestamp(tns, tsd, &opt, (NormMode)tns.opt_block);
216
217 if (!stripped)
218 {
219 tsd.set_timestamp(extract_32bits(opt.data) );
220 return TF_TSTAMP;
221 }
222 }
223 }
224 }
225 tsd.set_timestamp(0);
226 return TF_NONE;
227 }
228
validate_rst_seq_geq(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd)229 bool TcpNormalizer::validate_rst_seq_geq(
230 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
231 {
232 // FIXIT-M check for rcv_nxt == 0 is hack for uninitialized rcv_nxt
233 if ( ( tns.tracker->rcv_nxt == 0 ) || SEQ_GEQ(tsd.get_seq(), tns.tracker->rcv_nxt) )
234 return true;
235
236 return false;
237 }
238
validate_rst_end_seq_geq(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd)239 bool TcpNormalizer::validate_rst_end_seq_geq(
240 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
241 {
242 // FIXIT-M check for r_win_base == 0 is hack for uninitialized r_win_base
243 if ( tns.tracker->r_win_base == 0 )
244 return true;
245
246 if ( SEQ_GEQ(tsd.get_end_seq(), tns.tracker->r_win_base))
247 {
248 // reset must be admitted when window closed
249 if (SEQ_LEQ(tsd.get_seq(), tns.tracker->r_win_base + get_stream_window(tns, tsd)))
250 return true;
251 }
252
253 return false;
254 }
255
validate_rst_seq_eq(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd)256 bool TcpNormalizer::validate_rst_seq_eq(
257 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
258 {
259 uint32_t expected_seq = tns.tracker->r_win_base + tns.tracker->get_fin_seq_adjust();
260
261 if ( SEQ_EQ(tsd.get_seq(), expected_seq) )
262 return true;
263
264 return false;
265 }
266
267 // per rfc 793 a rst is valid if the seq number is in window
268 // for all states but syn-sent (handled above). however, we
269 // validate here based on how various implementations actually
270 // handle a rst.
validate_rst(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd)271 bool TcpNormalizer::validate_rst(
272 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
273 {
274 return validate_rst_seq_eq(tns, tsd);
275 }
276
validate_paws_timestamp(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd)277 int TcpNormalizer::validate_paws_timestamp(
278 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
279 {
280 const uint32_t peer_ts_last = tns.peer_tracker->get_ts_last();
281 if ( peer_ts_last && ( ( (int)( ( tsd.get_timestamp() - peer_ts_last ) + tns.paws_ts_fudge ) ) < 0 ) )
282 {
283 if ( tsd.get_pkt()->is_retry() )
284 {
285 // Retry packets can legitimately have old timestamps
286 // in TCP options (if a re-transmit comes in before
287 // the retry) so don't consider it an error.
288 tsd.set_timestamp(tns.peer_tracker->get_ts_last());
289 return ACTION_NOTHING;
290 }
291 else
292 {
293 /* bail, we've got a packet outside the PAWS window! */
294 tns.session->tel.set_tcp_event(EVENT_BAD_TIMESTAMP);
295 packet_dropper(tns, tsd, NORM_TCP_OPT);
296 return ACTION_BAD_PKT;
297 }
298 }
299 else if ( ( tns.peer_tracker->get_ts_last() != 0 )
300 && ( ( uint32_t )tsd.get_packet_timestamp() > tns.peer_tracker->get_ts_last_packet() +
301 PAWS_24DAYS ) )
302 {
303 /* this packet is from way too far into the future */
304 tns.session->tel.set_tcp_event(EVENT_BAD_TIMESTAMP);
305 packet_dropper(tns, tsd, NORM_TCP_OPT);
306 return ACTION_BAD_PKT;
307 }
308 else
309 return ACTION_NOTHING;
310 }
311
is_paws_ts_checked_required(TcpNormalizerState &,TcpSegmentDescriptor &)312 bool TcpNormalizer::is_paws_ts_checked_required(
313 TcpNormalizerState&, TcpSegmentDescriptor&)
314 {
315 return true;
316 }
317
validate_paws(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd)318 int TcpNormalizer::validate_paws(
319 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
320 {
321 tns.tcp_ts_flags = get_tcp_timestamp(tns, tsd, false);
322 if ( tns.tcp_ts_flags )
323 {
324 bool check_ts = is_paws_ts_checked_required(tns, tsd);
325
326 if ( check_ts )
327 return validate_paws_timestamp(tns, tsd);
328 else
329 return ACTION_NOTHING;
330 }
331 else
332 {
333 // we've got a packet with no timestamp, but 3whs indicated talker was doing
334 // timestamps. This breaks protocol, however, some servers still ack the packet
335 // with the missing timestamp. Log an alert, but continue to process the packet
336 tns.session->tel.set_tcp_event(EVENT_NO_TIMESTAMP);
337
338 /* Ignore the timestamp for this first packet, next one will checked. */
339 if ( tns.session->tcp_config->policy == StreamPolicy::OS_SOLARIS )
340 tns.tracker->clear_tf_flags(TF_TSTAMP);
341
342 packet_dropper(tns, tsd, NORM_TCP_OPT);
343 return ACTION_NOTHING;
344 }
345 }
346
handle_paws_no_timestamps(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd)347 int TcpNormalizer::handle_paws_no_timestamps(
348 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
349 {
350 tns.tcp_ts_flags = get_tcp_timestamp(tns, tsd, true);
351 if (tns.tcp_ts_flags)
352 {
353 if (!(tns.peer_tracker->get_tf_flags() & TF_TSTAMP))
354 {
355 // SYN skipped, may have missed talker's timestamp , so set it now.
356 if (tsd.get_timestamp() == 0)
357 tns.peer_tracker->set_tf_flags(TF_TSTAMP | TF_TSTAMP_ZERO);
358 else
359 tns.peer_tracker->set_tf_flags(TF_TSTAMP);
360 }
361
362 // Only valid to test this if listener is using timestamps. Otherwise, timestamp
363 // in this packet is not used, regardless of its value.
364 if ( ( tns.paws_drop_zero_ts && ( tsd.get_timestamp() == 0 ) ) &&
365 ( tns.tracker->get_tf_flags() & TF_TSTAMP ) )
366 {
367 tns.session->tel.set_tcp_event(EVENT_BAD_TIMESTAMP);
368 packet_dropper(tns, tsd, NORM_TCP_BLOCK);
369 return ACTION_BAD_PKT;
370 }
371 }
372
373 return ACTION_NOTHING;
374 }
375
handle_paws(TcpNormalizerState & tns,TcpSegmentDescriptor & tsd)376 int TcpNormalizer::handle_paws(
377 TcpNormalizerState& tns, TcpSegmentDescriptor& tsd)
378 {
379 if ( tsd.get_tcph()->is_rst() )
380 return ACTION_NOTHING;
381
382 #if 0
383 if ( tsd.get_tcph()->is_ack() && Normalize_IsEnabled(NORM_TCP_OPT) )
384 {
385 // FIXIT-L validate tsecr here (check that it was previously sent)
386 // checking for the most recent ts is easy enough must check if
387 // ts are up to date in retransmitted packets
388 }
389 #endif
390
391 if ((tns.peer_tracker->get_tf_flags() & TF_TSTAMP) &&
392 (tns.tracker->get_tf_flags() & TF_TSTAMP))
393 {
394 return validate_paws(tns, tsd);
395 }
396 else if (tsd.get_tcph()->is_syn_only())
397 {
398 tns.tcp_ts_flags = get_tcp_timestamp(tns, tsd, false);
399 if (tns.tcp_ts_flags)
400 tns.peer_tracker->set_tf_flags(TF_TSTAMP);
401
402 return ACTION_NOTHING;
403 }
404 else
405 {
406 return handle_paws_no_timestamps(tns, tsd);
407 }
408 }
409
set_urg_offset(TcpNormalizerState &,const tcp::TCPHdr * tcph,uint16_t dsize)410 uint16_t TcpNormalizer::set_urg_offset(
411 TcpNormalizerState&, const tcp::TCPHdr* tcph, uint16_t dsize)
412 {
413 uint16_t urg_offset = 0;
414
415 if (tcph->are_flags_set(TH_URG) )
416 {
417 urg_offset = tcph->urp();
418
419 // discard data from urgent pointer If urg pointer is beyond this packet,
420 // it's treated as a 0
421 if (urg_offset > dsize)
422 urg_offset = 0;
423 }
424
425 return urg_offset;
426 }
427
reset_stats()428 void TcpNormalizer::reset_stats()
429 {
430 for (int i = 0; i < PC_TCP_MAX; i++)
431 for (int j = 0; j < NORM_MODE_MAX; j++)
432 tcp_norm_stats[i][j] = 0;
433 }
434