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