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_closed.cc author davis mcpherson <davmcphe@cisco.com>
20 // Created on: Jul 30, 2015
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include "tcp_state_closed.h"
27 
28 #include "tcp_session.h"
29 
30 #ifdef UNIT_TEST
31 #include "catch/snort_catch.h"
32 #endif
33 
34 using namespace snort;
35 
TcpStateClosed(TcpStateMachine & tsm)36 TcpStateClosed::TcpStateClosed(TcpStateMachine& tsm) :
37     TcpStateHandler(TcpStreamTracker::TCP_CLOSED, tsm)
38 { }
39 
syn_sent(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)40 bool TcpStateClosed::syn_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
41 {
42     trk.session->check_for_repeated_syn(tsd);
43     return true;
44 }
45 
syn_recv(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)46 bool TcpStateClosed::syn_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
47 {
48     Flow* flow = tsd.get_flow();
49     flow->set_expire(tsd.get_pkt(), trk.session->tcp_config->session_timeout);
50     return true;
51 }
52 
ack_sent(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)53 bool TcpStateClosed::ack_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
54 {
55     trk.update_tracker_ack_sent(tsd);
56     return true;
57 }
58 
ack_recv(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)59 bool TcpStateClosed::ack_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
60 {
61     trk.update_tracker_ack_recv(tsd);
62     return true;
63 }
64 
data_seg_sent(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)65 bool TcpStateClosed::data_seg_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
66 {
67     Flow* flow = tsd.get_flow();
68 
69     trk.update_tracker_ack_sent(tsd);
70     // data on a segment when we're not accepting data any more alert!
71     if ( flow->get_session_flags() & SSNFLAG_RESET )
72     {
73         if ( trk.is_rst_pkt_sent() )
74             trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RESET);
75         else
76             trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD);
77     }
78     else
79         trk.session->tel.set_tcp_event(EVENT_DATA_ON_CLOSED);
80 
81     trk.session->mark_packet_for_drop(tsd);
82     return true;
83 }
84 
data_seg_recv(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)85 bool TcpStateClosed::data_seg_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
86 {
87     trk.update_tracker_ack_recv(tsd);
88     return true;
89 }
90 
fin_sent(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)91 bool TcpStateClosed::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
92 {
93     trk.update_tracker_ack_sent(tsd);
94     return true;
95 }
96 
fin_recv(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)97 bool TcpStateClosed::fin_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
98 {
99     trk.update_tracker_ack_recv(tsd);
100 
101     if( tsd.is_data_segment() )
102     {
103         if ( trk.is_rst_pkt_sent() )
104             trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RESET);
105         else
106             trk.session->tel.set_tcp_event(EVENT_DATA_AFTER_RST_RCVD);
107     }
108     return true;
109 }
110 
rst_recv(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)111 bool TcpStateClosed::rst_recv(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
112 {
113     if ( trk.update_on_rst_recv(tsd) )
114     {
115         trk.session->update_session_on_rst(tsd, false);
116         trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
117         trk.session->set_pkt_action_flag(ACTION_RST);
118     }
119 
120     return true;
121 }
122 
do_pre_sm_packet_actions(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)123 bool TcpStateClosed::do_pre_sm_packet_actions(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
124 {
125     return trk.session->validate_packet_established_session(tsd);
126 }
127 
do_post_sm_packet_actions(TcpSegmentDescriptor & tsd,TcpStreamTracker & trk)128 bool TcpStateClosed::do_post_sm_packet_actions(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
129 {
130     trk.session->update_paws_timestamps(tsd);
131     trk.session->check_for_window_slam(tsd);
132 
133     if ( trk.get_tcp_event() != TcpStreamTracker::TCP_FIN_RECV_EVENT )
134     {
135         TcpStreamTracker::TcpState talker_state = trk.session->get_talker_state(tsd);
136         Flow* flow = tsd.get_flow();
137 
138         if ( ( talker_state == TcpStreamTracker::TCP_TIME_WAIT or
139                talker_state == TcpStreamTracker::TCP_CLOSED ) or !flow->two_way_traffic() )
140         {
141             // The last ACK is a part of the session. Delete the session after processing is
142             // complete.
143             trk.session->clear_session(false, true, false, tsd.is_meta_ack_packet() ? nullptr : tsd.get_pkt() );
144             flow->session_state |= STREAM_STATE_CLOSED;
145             trk.session->set_pkt_action_flag(ACTION_LWSSN_CLOSED);
146         }
147     }
148 
149     return true;
150 }
151 
152