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