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_state_last_ack.cc author davis mcpherson <davmcphe@cisco.com>
20 // Created on: Aug 5, 2015
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include "tcp_state_last_ack.h"
27 
28 #include "tcp_normalizers.h"
29 #include "tcp_session.h"
30 
31 using namespace snort;
32 
TcpStateLastAck(TcpStateMachine & tsm)33 TcpStateLastAck::TcpStateLastAck(TcpStateMachine& tsm) :
34     TcpStateHandler(TcpStreamTracker::TCP_LAST_ACK, tsm)
35 { }
36 
syn_sent(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)37 bool TcpStateLastAck::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
38 {
39     trk.session->check_for_repeated_syn(tsd);
40     return true;
41 }
42 
syn_recv(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)43 bool TcpStateLastAck::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
44 {
45     trk.normalizer.ecn_tracker(tsd.get_tcph(), trk.session->tcp_config->require_3whs());
46     if ( tsd.is_data_segment() )
47         trk.session->handle_data_on_syn(tsd);
48     return true;
49 }
50 
ack_sent(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)51 bool TcpStateLastAck::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
52 {
53     trk.update_tracker_ack_sent(tsd);
54     return true;
55 }
56 
ack_recv(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)57 bool TcpStateLastAck::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
58 {
59     trk.update_tracker_ack_recv(tsd);
60     if ( SEQ_EQ(tsd.get_ack(), trk.get_snd_nxt() ) )
61         trk.set_tcp_state(TcpStreamTracker::TCP_CLOSED);
62     return true;
63 }
64 
data_seg_sent(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)65 bool TcpStateLastAck::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
66 {
67     trk.update_tracker_ack_sent(tsd);
68     return true;
69 }
70 
data_seg_recv(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)71 bool TcpStateLastAck::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
72 {
73     trk.update_tracker_ack_recv(tsd);
74     if ( SEQ_EQ(tsd.get_ack(), trk.get_snd_nxt() ) )
75         trk.set_tcp_state(TcpStreamTracker::TCP_CLOSED);
76     return true;
77 }
78 
fin_sent(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)79 bool TcpStateLastAck::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
80 {
81     trk.update_tracker_ack_sent(tsd);
82     return true;
83 }
84 
fin_recv(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)85 bool TcpStateLastAck::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
86 {
87     Flow* flow = tsd.get_flow();
88 
89     trk.update_tracker_ack_recv(tsd);
90     if ( SEQ_EQ(tsd.get_ack(), trk.get_snd_nxt() ) )
91         trk.set_tcp_state(TcpStreamTracker::TCP_CLOSED);
92 
93     if ( !flow->two_way_traffic() )
94         trk.set_tf_flags(TF_FORCE_FLUSH);
95     return true;
96 }
97 
rst_recv(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)98 bool TcpStateLastAck::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
99 {
100     if ( trk.update_on_rst_recv(tsd) )
101     {
102         trk.session->update_session_on_rst(tsd, false);
103         trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
104         trk.session->set_pkt_action_flag(ACTION_RST);
105     }
106 
107     // FIXIT-L might be good to create alert specific to RST with data
108     if ( tsd.is_data_segment() )
109         trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD);
110     return true;
111 }
112 
do_pre_sm_packet_actions(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)113 bool TcpStateLastAck::do_pre_sm_packet_actions(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
114 {
115     return trk.session->validate_packet_established_session(tsd);
116 }
117 
do_post_sm_packet_actions(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)118 bool TcpStateLastAck::do_post_sm_packet_actions(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
119 {
120     trk.session->update_paws_timestamps(tsd);
121     trk.session->check_for_window_slam(tsd);
122 
123     if ( ( trk.session->get_listener_state(tsd) == TcpStreamTracker::TCP_CLOSED ) &&
124         ( trk.get_tcp_event() != TcpStreamTracker::TCP_FIN_RECV_EVENT ) )
125     {
126         TcpStreamTracker::TcpState talker_state = trk.session->get_talker_state(tsd);
127         Flow* flow = tsd.get_flow();
128 
129         if ( ( talker_state == TcpStreamTracker::TCP_TIME_WAIT )
130             || ( talker_state == TcpStreamTracker::TCP_CLOSED ) )
131         {
132             // The last ACK is a part of the session. Delete session after processing the ack
133             trk.session->clear_session(false, true, false, tsd.is_meta_ack_packet() ? nullptr : tsd.get_pkt() );
134             flow->session_state |= STREAM_STATE_CLOSED;
135             trk.session->set_pkt_action_flag(ACTION_LWSSN_CLOSED);
136         }
137     }
138 
139     return true;
140 }
141 
142