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