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_stream_session.cc author davis mcpherson <davmcphe@cisco.com>
20 // Created on: Feb 18, 2016
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include "tcp_stream_session.h"
27 
28 #include "log/messages.h"
29 #include "stream/tcp/tcp_ha.h"
30 
31 using namespace snort;
32 
TcpStreamSession(Flow * f)33 TcpStreamSession::TcpStreamSession(Flow* f)
34     : Session(f), client(true), server(false)
35 { }
36 
37 TcpStreamSession::~TcpStreamSession() = default;
38 
init_new_tcp_session(TcpSegmentDescriptor & tsd)39 void TcpStreamSession::init_new_tcp_session(TcpSegmentDescriptor& tsd)
40 {
41     Packet* p = tsd.get_pkt();
42 
43     flow->pkt_type = p->type();
44     flow->ip_proto = (uint8_t)p->get_ip_proto_next();
45 
46     /* New session, previous was marked as reset.  Clear the reset flag. */
47     flow->clear_session_flags(SSNFLAG_RESET);
48 
49     flow->set_expire(p, flow->default_session_timeout);
50 
51     update_perf_base_state(TcpStreamTracker::TCP_SYN_SENT);
52 
53     tcp_init = true;
54     lws_init = true;
55 }
56 
update_session_on_syn_ack()57 void TcpStreamSession::update_session_on_syn_ack()
58 {
59     /* If session is already marked as established */
60     if ( !(flow->session_state & STREAM_STATE_ESTABLISHED) )
61     {
62         /* SYN-ACK from server */
63         if (flow->session_state != STREAM_STATE_NONE)
64         {
65             flow->session_state |= STREAM_STATE_SYN_ACK;
66             update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
67         }
68     }
69 }
70 
update_session_on_ack()71 void TcpStreamSession::update_session_on_ack()
72 {
73     /* If session is already marked as established */
74     if ( !(flow->session_state & STREAM_STATE_ESTABLISHED) )
75     {
76         if ( flow->session_state & STREAM_STATE_SYN_ACK )
77         {
78             flow->session_state |= STREAM_STATE_ACK | STREAM_STATE_ESTABLISHED;
79             update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
80         }
81     }
82 }
83 
update_session_on_server_packet(TcpSegmentDescriptor & tsd)84 void TcpStreamSession::update_session_on_server_packet(TcpSegmentDescriptor& tsd)
85 {
86     flow->set_session_flags(SSNFLAG_SEEN_SERVER);
87     tsd.set_talker(server);
88     tsd.set_listener(client);
89 
90     /* If we picked this guy up midstream, finish the initialization */
91     if ( !(flow->session_state & STREAM_STATE_ESTABLISHED)
92         && (flow->session_state & STREAM_STATE_MIDSTREAM) )
93     {
94         if ( tsd.get_tcph()->are_flags_set(TH_ECE)
95              && (flow->get_session_flags() & SSNFLAG_ECN_CLIENT_QUERY) )
96             flow->set_session_flags(SSNFLAG_ECN_SERVER_REPLY);
97 
98         if ( flow->get_session_flags() & SSNFLAG_SEEN_CLIENT )
99         {
100             // should TCP state go to established too?
101             flow->session_state |= STREAM_STATE_ESTABLISHED;
102             flow->set_session_flags(SSNFLAG_ESTABLISHED);
103             update_perf_base_state(TcpStreamTracker::TCP_ESTABLISHED);
104         }
105     }
106 
107     if ( !flow->inner_server_ttl && !tsd.is_meta_ack_packet() )
108         flow->set_ttl(tsd.get_pkt(), false);
109 }
110 
update_session_on_client_packet(TcpSegmentDescriptor & tsd)111 void TcpStreamSession::update_session_on_client_packet(TcpSegmentDescriptor& tsd)
112 {
113     /* if we got here we have seen the SYN already... */
114     flow->set_session_flags(SSNFLAG_SEEN_CLIENT);
115     tsd.set_talker(client);
116     tsd.set_listener(server);
117 
118     if ( !( flow->session_state & STREAM_STATE_ESTABLISHED )
119         && ( flow->session_state & STREAM_STATE_MIDSTREAM ) )
120     {
121         /* Midstream and seen server. */
122         if ( flow->get_session_flags() & SSNFLAG_SEEN_SERVER )
123         {
124             flow->session_state |= STREAM_STATE_ESTABLISHED;
125             flow->set_session_flags(SSNFLAG_ESTABLISHED);
126         }
127     }
128 
129     if ( !flow->inner_client_ttl && !tsd.is_meta_ack_packet() )
130         flow->set_ttl(tsd.get_pkt(), true);
131 }
132 
set_no_ack(bool b)133 void TcpStreamSession::set_no_ack(bool b)
134 {
135     if ( server.get_flush_policy() == STREAM_FLPOLICY_ON_DATA and
136          client.get_flush_policy() == STREAM_FLPOLICY_ON_DATA )
137     {
138         no_ack = b;
139     }
140 }
141 
disable_reassembly(Flow * f)142 void TcpStreamSession::disable_reassembly(Flow* f)
143 {
144     client.set_splitter((StreamSplitter*)nullptr);
145     server.set_splitter((StreamSplitter*)nullptr);
146 
147     client.reassembler.purge_segment_list();
148     server.reassembler.purge_segment_list();
149 
150     client.set_flush_policy(STREAM_FLPOLICY_IGNORE);
151     server.set_flush_policy(STREAM_FLPOLICY_IGNORE);
152 
153     client.finalize_held_packet(f);
154     server.finalize_held_packet(f);
155 }
156 
get_reassembly_direction()157 uint8_t TcpStreamSession::get_reassembly_direction()
158 {
159     uint8_t dir = SSN_DIR_NONE;
160 
161     if ( server.get_flush_policy() != STREAM_FLPOLICY_IGNORE )
162         dir |= SSN_DIR_FROM_CLIENT;
163 
164     if ( client.get_flush_policy() != STREAM_FLPOLICY_IGNORE )
165         dir |= SSN_DIR_FROM_SERVER;
166 
167     return dir;
168 }
169 
is_sequenced(uint8_t dir)170 bool TcpStreamSession::is_sequenced(uint8_t dir)
171 {
172     if ( dir & SSN_DIR_FROM_CLIENT )
173     {
174         if ( server.get_tf_flags() & ( TF_MISSING_PREV_PKT | TF_PKT_MISSED ) )
175             return false;
176     }
177 
178     if ( dir & SSN_DIR_FROM_SERVER )
179     {
180         if ( client.get_tf_flags() & ( TF_MISSING_PREV_PKT | TF_PKT_MISSED ) )
181             return false;
182     }
183 
184     return true;
185 }
186 
187 /* This will falsely return SSN_MISSING_BEFORE on the first reassembled
188  * packet if reassembly for this direction was set mid-session */
missing_in_reassembled(uint8_t dir)189 uint8_t TcpStreamSession::missing_in_reassembled(uint8_t dir)
190 {
191     if ( dir & SSN_DIR_FROM_CLIENT )
192     {
193         if ( (server.get_tf_flags() & TF_MISSING_PKT)
194             && (server.get_tf_flags() & TF_MISSING_PREV_PKT) )
195             return SSN_MISSING_BOTH;
196         else if ( server.get_tf_flags() & TF_MISSING_PREV_PKT )
197             return SSN_MISSING_BEFORE;
198         else if ( server.get_tf_flags() & TF_MISSING_PKT )
199             return SSN_MISSING_AFTER;
200     }
201     else if ( dir & SSN_DIR_FROM_SERVER )
202     {
203         if ( (client.get_tf_flags() & TF_MISSING_PKT)
204             && (client.get_tf_flags() & TF_MISSING_PREV_PKT) )
205             return SSN_MISSING_BOTH;
206         else if ( client.get_tf_flags() & TF_MISSING_PREV_PKT )
207             return SSN_MISSING_BEFORE;
208         else if ( client.get_tf_flags() & TF_MISSING_PKT )
209             return SSN_MISSING_AFTER;
210     }
211 
212     return SSN_MISSING_NONE;
213 }
214 
are_packets_missing(uint8_t dir)215 bool TcpStreamSession::are_packets_missing(uint8_t dir)
216 {
217     if ( dir & SSN_DIR_FROM_CLIENT )
218     {
219         if ( server.get_tf_flags() & TF_PKT_MISSED )
220             return true;
221     }
222 
223     if ( dir & SSN_DIR_FROM_SERVER )
224     {
225         if ( client.get_tf_flags() & TF_PKT_MISSED )
226             return true;
227     }
228 
229     return false;
230 }
231 
are_client_segments_queued()232 bool TcpStreamSession::are_client_segments_queued()
233 {
234     return client.reassembler.is_segment_pending_flush();
235 }
236 
add_alert(Packet * p,uint32_t gid,uint32_t sid)237 bool TcpStreamSession::add_alert(Packet* p, uint32_t gid, uint32_t sid)
238 {
239     TcpReassemblerPolicy& trp = p->ptrs.ip_api.get_src()->equals(flow->client_ip) ?
240         server.reassembler : client.reassembler;
241 
242     return trp.add_alert(gid, sid);
243 }
244 
check_alerted(Packet * p,uint32_t gid,uint32_t sid)245 bool TcpStreamSession::check_alerted(Packet* p, uint32_t gid, uint32_t sid)
246 {
247     // only check for alert on wire packet if this when processing a rebuilt packet
248     if ( !(p->packet_flags & PKT_REBUILT_STREAM) )
249         return false;
250 
251     TcpReassemblerPolicy& trp = p->ptrs.ip_api.get_src()->equals(flow->client_ip) ?
252         server.reassembler : client.reassembler;
253 
254     return trp.check_alerted(gid, sid);
255 }
256 
update_alert(Packet * p,uint32_t gid,uint32_t sid,uint32_t event_id,uint32_t event_second)257 int TcpStreamSession::update_alert(Packet* p, uint32_t gid, uint32_t sid,
258     uint32_t event_id, uint32_t event_second)
259 {
260     TcpReassemblerPolicy& trp = p->ptrs.ip_api.get_src()->equals(flow->client_ip) ?
261         server.reassembler : client.reassembler;
262 
263     return trp.update_alert(gid, sid, event_id, event_second);
264 }
265 
set_packet_action_to_hold(Packet * p)266 bool TcpStreamSession::set_packet_action_to_hold(Packet* p)
267 {
268     if ( p->is_from_client() )
269     {
270         held_packet_dir = SSN_DIR_FROM_CLIENT;
271         return server.set_held_packet(p);
272     }
273     else
274     {
275         held_packet_dir = SSN_DIR_FROM_SERVER;
276         return client.set_held_packet(p);
277     }
278 }
279 
set_packet_header_foo(const TcpSegmentDescriptor & tsd)280 void TcpStreamSession::set_packet_header_foo(const TcpSegmentDescriptor& tsd)
281 {
282     const Packet* p = tsd.get_pkt();
283 
284     if ( tsd.is_packet_from_client() || (p->pkth->egress_index == DAQ_PKTHDR_UNKNOWN
285          && p->pkth->egress_group == DAQ_PKTHDR_UNKNOWN) )
286     {
287         ingress_index = p->pkth->ingress_index;
288         ingress_group = p->pkth->ingress_group;
289         // ssn egress may be unknown, but will be correct
290         egress_index = p->pkth->egress_index;
291         egress_group = p->pkth->egress_group;
292     }
293     else
294     {
295         egress_index = p->pkth->ingress_index;
296         egress_group = p->pkth->ingress_group;
297         ingress_index = p->pkth->egress_index;
298         ingress_group = p->pkth->egress_group;
299     }
300 
301     daq_flags = p->pkth->flags;
302     address_space_id = p->pkth->address_space_id;
303 }
304 
get_packet_header_foo(DAQ_PktHdr_t * pkth,uint32_t dir)305 void TcpStreamSession::get_packet_header_foo(DAQ_PktHdr_t* pkth, uint32_t dir)
306 {
307     if ( (dir & PKT_FROM_CLIENT) || (egress_index == DAQ_PKTHDR_UNKNOWN &&
308          egress_group == DAQ_PKTHDR_UNKNOWN) )
309     {
310         pkth->ingress_index = ingress_index;
311         pkth->ingress_group = ingress_group;
312         pkth->egress_index = egress_index;
313         pkth->egress_group = egress_group;
314     }
315     else
316     {
317         pkth->ingress_index = egress_index;
318         pkth->ingress_group = egress_group;
319         pkth->egress_index = ingress_index;
320         pkth->egress_group = ingress_group;
321     }
322     pkth->opaque = 0;
323     pkth->flags = daq_flags;
324     pkth->address_space_id = address_space_id;
325 }
326 
reset()327 void TcpStreamSession::reset()
328 {
329     if ( tcp_init )
330         clear_session(true, false, false );
331 }
332 
cleanup(Packet * p)333 void TcpStreamSession::cleanup(Packet* p)
334 {
335     if ( cleaning )
336         return;
337 
338     cleaning = true;
339     clear_session(true, true, false, p);
340     client.normalizer.reset();
341     server.normalizer.reset();
342     client.reassembler.reset();
343     server.reassembler.reset();
344     cleaning = false;
345 }
346 
clear()347 void TcpStreamSession::clear()
348 {
349     if ( tcp_init )
350         clear_session( true, false, false );
351 
352     TcpHAManager::process_deletion(*flow);
353 }
354 
set_splitter(bool to_server,StreamSplitter * ss)355 void TcpStreamSession::set_splitter(bool to_server, StreamSplitter* ss)
356 {
357     TcpStreamTracker& trk = ( to_server ) ? server : client;
358 
359     trk.set_splitter(ss);
360 }
361 
get_mss(bool to_server) const362 uint16_t TcpStreamSession::get_mss(bool to_server) const
363 {
364     const TcpStreamTracker& trk = (to_server) ? client : server;
365 
366     return trk.get_mss();
367 }
368 
get_tcp_options_len(bool to_server) const369 uint8_t TcpStreamSession::get_tcp_options_len(bool to_server) const
370 {
371     const TcpStreamTracker& trk = (to_server) ? client : server;
372 
373     return trk.get_tcp_options_len();
374 }
375 
get_splitter(bool to_server)376 StreamSplitter* TcpStreamSession::get_splitter(bool to_server)
377 {
378     if ( to_server )
379         return server.get_splitter();
380     else
381         return client.get_splitter();
382 }
383 
start_proxy()384 void TcpStreamSession::start_proxy()
385 { tcp_config->policy = StreamPolicy::OS_PROXY; }
386 
387