00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
00003 // Copyright (C) 2005-2013 Sourcefire, Inc.
00004 //
00005 // This program is free software; you can redistribute it and/or modify it
00006 // under the terms of the GNU General Public License Version 2 as published
00007 // by the Free Software Foundation. You may not use, modify or distribute
00008 // this program under any other version of the GNU General Public License.
00009 //
00010 // This program is distributed in the hope that it will be useful, but
00011 // WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00013 // General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License along
00016 // with this program; if not, write to the Free Software Foundation, Inc.,
00017 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018 //--------------------------------------------------------------------------
00019
00020 /*
00021 * stream_tcp.c authors:
00022 * Martin Roesch <roesch@sourcefire.com>
00023 * Steven Sturges <ssturges@sourcefire.com>
00024 * Russ Combs <rcombs@sourcefire.com>
00025 */
00026
00027 /*
00028 * FIXITs:
00029 * - midstream ssn pickup (done, SAS 10/14/2005)
00030 * - syn flood protection (done, SAS 9/27/2005)
00031 *
00032 * - review policy anomaly detection
00033 * + URG pointer (TODO)
00034 * + data on SYN (done, SAS 10/12/2005)
00035 * + data on FIN (done, SAS 10/12/2005)
00036 * + data after FIN (done, SAS 10/13/2005)
00037 * + window scaling/window size max (done, SAS 10/13/2005)
00038 * + PAWS, TCP Timestamps (done, SAS 10/12/2005)
00039 *
00040 * - session shutdown/Reset handling (done, SAS)
00041 * - flush policy for Window/Consumed
00042 * - limit on number of overlapping packets (done, SAS)
00043 */
00044
00045 #ifdef HAVE_CONFIG_H
00046 #include "config.h"
00047 #endif
00048
00049 #include "tcp_session.h"
00050
00051 #include "detection/detection_engine.h"
00052 #include "detection/rules.h"
00053 #include "log/log.h"
00054 #include "perf_monitor/flow_ip_tracker.h"
00055 #include "profiler/profiler.h"
00056 #include "protocols/eth.h"
00057
00058 #include "stream_tcp.h"
00059 #include "tcp_debug_trace.h"
00060 #include "tcp_ha.h"
00061 #include "tcp_module.h"
00062 #include "tcp_normalizers.h"
00063 #include "tcp_reassemblers.h"
00064 #include "tcp_stream_state_machine.h"
00065
00066 DEBUG_WRAP(static THREAD_LOCAL const char* t_name = NULL; static THREAD_LOCAL const char* l_name = NULL; )
00067
00068 TcpSession::TcpSession(Flow* flow) : TcpStreamSession(flow)
00069 {
00070 tsm = TcpStreamStateMachine::get_instance();
00071 client = new TcpTracker(true, this);
00072 server = new TcpTracker(false, this);
00073 }
00074
00075 TcpSession::~TcpSession()
00076 {
00077 if (tcp_init)
00078 clear_session(true, false, false);
00079
00080 delete client;
00081 delete server;
00082 }
00083
00084 bool TcpSession::setup(Packet* p)
00085 {
00086 TcpStreamSession::setup(p);
00087
00088 client->init_toolbox();
00089 server->init_toolbox();
00090
00091 SESSION_STATS_ADD(tcpStats);
00092 return true;
00093 }
00094
00095 // FIXIT-M once TcpReassembler interface is abstract class move this to base class
00096 void TcpSession::restart(Packet* p)
00097 {
00098 // sanity check since this is called externally
00099 assert(p);
00100 assert(p->ptrs.tcph);
00101 assert(p->flow == flow);
00102
00103 DetectionEngine::onload(flow);
00104 TcpStreamTracker* talker, * listener;
00105
00106 if (p->is_from_server())
00107 {
00108 talker = server;
00109 listener = client;
00110 }
00111 else
00112 {
00113 talker = client;
00114 listener = server;
00115 }
00116
00117 // FIXIT-H on data / on ack must be based on flush policy
00118 if (p->dsize > 0)
00119 listener->reassembler->flush_on_data_policy(p);
00120
00121 if (p->ptrs.tcph->is_ack())
00122 talker->reassembler->flush_on_ack_policy(p);
00123 }
00124
00125 //-------------------------------------------------------------------------
00126 // when client ports are configured, that means c2s and is stored on the
00127 // client side; when the session starts, the server policy is obtained from
00128 // the client side because segments are stored on the receiving side.
00129 //
00130 // this could be improved further by storing the c2s policy on the server
00131 // side and then obtaining server policy from the server on session
00132 // startup.
00133 //
00134 // either way, this client / server distinction must be kept in mind to
00135 // make sense of the code in this file.
00136 //-------------------------------------------------------------------------
00137
00138 void TcpSession::clear_session(bool free_flow_data, bool flush_segments, bool restart, Packet* p)
00139 {
00140 assert(!p or p->flow == flow);
00141 DetectionEngine::onload(flow);
00142
00143 if ( client->reassembler )
00144 {
00145 if ( flush_segments )
00146 client->reassembler->flush_queued_segments(flow, true, p);
00147 client->reassembler->purge_segment_list();
00148 }
00149
00150 if ( server->reassembler )
00151 {
00152 if ( flush_segments )
00153 server->reassembler->flush_queued_segments(flow, true, p);
00154 server->reassembler->purge_segment_list();
00155 }
00156
00157 if ( tcp_init )
00158 tcpStats.released++;
00159 else if ( lws_init )
00160 tcpStats.no_pickups++;
00161 else
00162 return;
00163
00164 update_perf_base_state(TcpStreamTracker::TCP_CLOSED);
00165
00166 if ( restart )
00167 {
00168 flow->restart(free_flow_data);
00169 paf_reset(&client->paf_state);
00170 paf_reset(&server->paf_state);
00171
00172 }
00173 else
00174 {
00175 flow->clear(free_flow_data);
00176 paf_clear(&client->paf_state);
00177 paf_clear(&server->paf_state);
00178 }
00179
00180 set_splitter(true, nullptr);
00181 set_splitter(false, nullptr);
00182
00183 tel.log_internal_event(INTERNAL_EVENT_SESSION_DEL);
00184
00185 lws_init = false;
00186 tcp_init = false;
00187 }
00188
00189 void TcpSession::update_perf_base_state(char newState)
00190 {
00191 uint32_t session_flags = flow->get_session_flags();
00192 switch ( newState )
00193 {
00194 case TcpStreamTracker::TCP_SYN_SENT:
00195 if ( !( session_flags & SSNFLAG_COUNTED_INITIALIZE ) )
00196 {
00197 tcpStats.sessions_initializing++;
00198 session_flags |= SSNFLAG_COUNTED_INITIALIZE;
00199 }
00200 break;
00201
00202 case TcpStreamTracker::TCP_ESTABLISHED:
00203 if ( !( session_flags & SSNFLAG_COUNTED_ESTABLISH ) )
00204 {
00205 tcpStats.sessions_established++;
00206 if ( perfmon_config && ( perfmon_config->perf_flags & PERF_FLOWIP ) )
00207 perf_flow_ip->update_state(&flow->client_ip,
00208 &flow->server_ip, SFS_STATE_TCP_ESTABLISHED);
00209
00210 session_flags |= SSNFLAG_COUNTED_ESTABLISH;
00211 tel.log_internal_event(INTERNAL_EVENT_SESSION_ADD);
00212 if ( ( session_flags & SSNFLAG_COUNTED_INITIALIZE )
00213 && !( session_flags & SSNFLAG_COUNTED_CLOSING ) )
00214 {
00215 assert(tcpStats.sessions_initializing);
00216 tcpStats.sessions_initializing--;
00217 }
00218 }
00219 break;
00220
00221 case TcpStreamTracker::TCP_CLOSING:
00222 if ( !( session_flags & SSNFLAG_COUNTED_CLOSING ) )
00223 {
00224 tcpStats.sessions_closing++;
00225 session_flags |= SSNFLAG_COUNTED_CLOSING;
00226
00227 if ( session_flags & SSNFLAG_COUNTED_ESTABLISH )
00228 {
00229 assert(tcpStats.sessions_established);
00230 tcpStats.sessions_established--;
00231
00232 if (perfmon_config && (perfmon_config->perf_flags & PERF_FLOWIP))
00233 perf_flow_ip->update_state(&flow->client_ip, &flow->server_ip,
00234 SFS_STATE_TCP_CLOSED);
00235 }
00236 else if ( session_flags & SSNFLAG_COUNTED_INITIALIZE )
00237 {
00238 assert(tcpStats.sessions_initializing);
00239 tcpStats.sessions_initializing--;
00240 }
00241 }
00242 break;
00243
00244 case TcpStreamTracker::TCP_CLOSED:
00245 if ( !( session_flags & SSNFLAG_COUNTED_CLOSED ) )
00246 {
00247 session_flags |= SSNFLAG_COUNTED_CLOSED;
00248
00249 if ( session_flags & SSNFLAG_COUNTED_CLOSING )
00250 {
00251 assert(tcpStats.sessions_closing);
00252 tcpStats.sessions_closing--;
00253 }
00254 else if ( session_flags & SSNFLAG_COUNTED_ESTABLISH )
00255 {
00256 assert(tcpStats.sessions_established);
00257 tcpStats.sessions_established--;
00258
00259 if ( perfmon_config && ( perfmon_config->perf_flags & PERF_FLOWIP ) )
00260 perf_flow_ip->update_state(&flow->client_ip,
00261 &flow->server_ip, SFS_STATE_TCP_CLOSED);
00262 }
00263 else if ( session_flags & SSNFLAG_COUNTED_INITIALIZE )
00264 {
00265 assert(tcpStats.sessions_initializing);
00266 tcpStats.sessions_initializing--;
00267 }
00268 }
00269 break;
00270
00271 default:
00272 break;
00273 }
00274
00275 flow->update_session_flags(session_flags);
00276 }
00277
00278 bool TcpSession::flow_exceeds_config_thresholds(TcpSegmentDescriptor& tsd)
00279 {
00280 if ( listener->flush_policy == STREAM_FLPOLICY_IGNORE )
00281 {
00282 DebugMessage(DEBUG_STREAM_STATE, "Ignoring segment due to IGNORE flush_policy\n");
00283 return true;
00284 }
00285
00286 // FIXIT-H any discards must be counted and in many cases alerted as well
00287 // (count all but alert at most once per flow)
00288 // three cases in this function; look for others
00289 if ( ( config->flags & STREAM_CONFIG_NO_ASYNC_REASSEMBLY ) && !flow->two_way_traffic() )
00290 return true;
00291
00292 if ( config->max_consec_small_segs
00293 && ( tsd.get_seg_len() < config->max_consec_small_seg_size ) )
00294 {
00295 listener->small_seg_count++;
00296
00297 if ( listener->small_seg_count > config->max_consec_small_segs )
00298 {
00299 /* Above threshold, log it... in this TCP policy,
00300 * action controlled by preprocessor rule. */
00301 tel.set_tcp_event(EVENT_MAX_SMALL_SEGS_EXCEEDED);
00302 /* Reset counter, so we're not too noisy */
00303 listener->small_seg_count = 0;
00304 }
00305 }
00306
00307 if ( config->max_queued_bytes
00308 && ( listener->reassembler->get_seg_bytes_total() > config->max_queued_bytes ) )
00309 {
00310 tcpStats.exceeded_max_bytes++;
00311 // FIXIT-H add one alert per flow per above
00312 return true;
00313 }
00314
00315 if ( config->max_queued_segs
00316 && ( listener->reassembler->get_seg_count() + 1 > config->max_queued_segs ) )
00317 {
00318 tcpStats.exceeded_max_segs++;
00319 // FIXIT-H add one alert per flow per above
00320 return true;
00321 }
00322
00323 return false;
00324 }
00325
00326 void TcpSession::process_tcp_stream(TcpSegmentDescriptor& tsd)
00327 {
00328 DebugFormat(DEBUG_STREAM_STATE, "In ProcessTcpStream(), %d bytes to queue\n",
00329 tsd.get_seg_len());
00330
00331 if (tsd.get_pkt()->packet_flags & PKT_IGNORE)
00332 return;
00333
00334 SetPacketHeaderFoo(tsd.get_pkt() );
00335
00336 if ( flow_exceeds_config_thresholds(tsd) )
00337 return;
00338
00339 DebugMessage(DEBUG_STREAM_STATE, "queuing segment\n");
00340 listener->reassembler->queue_packet_for_reassembly(tsd);
00341
00342 // Alert if overlap limit exceeded
00343 if ( ( config->overlap_limit )
00344 && ( listener->reassembler->get_overlap_count() > config->overlap_limit ) )
00345 {
00346 tel.set_tcp_event(EVENT_EXCESSIVE_OVERLAP);
00347 listener->reassembler->set_overlap_count(0);
00348 }
00349 }
00350
00351 void TcpSession::check_fin_transition_status(TcpSegmentDescriptor& tsd)
00352 {
00353 if((tsd.get_seg_len() != 0) &&
00354 SEQ_EQ(listener->get_fin_final_seq(), listener->r_nxt_ack))
00355 {
00356 listener->set_tcp_event(TcpStreamTracker::TCP_FIN_RECV_EVENT);
00357 talker->set_tcp_event(TcpStreamTracker::TCP_FIN_SENT_EVENT);
00358 listener->inorder_fin = true;
00359 }
00360 }
00361
00362
00363 int TcpSession::process_tcp_data(TcpSegmentDescriptor& tsd)
00364 {
00365 Profile profile(s5TcpDataPerfStats);
00366
00367 const tcp::TCPHdr* tcph = tsd.get_tcph();
00368 uint32_t seq = tsd.get_seg_seq();
00369
00370 if ( tcph->is_syn() )
00371 {
00372 if (listener->normalizer->get_os_policy() == StreamPolicy::OS_MACOS)
00373 seq++;
00374
00375 else
00376 {
00377 DebugMessage(DEBUG_STREAM_STATE, "Bailing, data on SYN, not MAC Policy!\n");
00378 listener->normalizer->trim_syn_payload(tsd);
00379 return STREAM_UNALIGNED;
00380 }
00381 }
00382
00383 /* we're aligned, so that's nice anyway */
00384 if (seq == listener->r_nxt_ack)
00385 {
00386 /* check if we're in the window */
00387 if (config->policy != StreamPolicy::OS_PROXY
00388 and listener->normalizer->get_stream_window(tsd) == 0)
00389 {
00390 DebugMessage(DEBUG_STREAM_STATE, "Bailing, we're out of the window!\n");
00391 listener->normalizer->trim_win_payload(tsd);
00392 return STREAM_UNALIGNED;
00393 }
00394
00395 /* move the ack boundary up, this is the only way we'll accept data */
00396 // FIXIT-L for ips, must move all the way to first hole or right end
00397 listener->r_nxt_ack = tsd.get_end_seq();
00398
00399 if (tsd.get_seg_len() != 0)
00400 {
00401 if (!( flow->get_session_flags() & SSNFLAG_STREAM_ORDER_BAD))
00402 tsd.get_pkt()->packet_flags |= PKT_STREAM_ORDER_OK;
00403
00404 process_tcp_stream(tsd);
00405 /* set flags to session flags */
00406
00407 return STREAM_ALIGNED;
00408 }
00409 }
00410 else
00411 {
00412 // pkt is out of order, do some target-based shizzle here...
00413 // NO, we don't want to simply bail. Some platforms favor unack'd dup data over the
00414 // original data. Let the reassembly policy decide how to handle the overlapping data.
00415 // See HP, Solaris, et al. for those that favor duplicate data over the original in
00416 // some cases.
00417 DebugFormat(DEBUG_STREAM_STATE,
00418 "out of order segment (tsd.seq: 0x%X l->r_nxt_ack: 0x%X!\n",
00419 tsd.get_seg_seq(), listener->r_nxt_ack);
00420
00421 /* check if we're in the window */
00422 if (config->policy != StreamPolicy::OS_PROXY
00423 and listener->normalizer->get_stream_window(tsd) == 0)
00424 {
00425 DebugMessage(DEBUG_STREAM_STATE, "Bailing, we're out of the window!\n");
00426 listener->normalizer->trim_win_payload(tsd);
00427 return STREAM_UNALIGNED;
00428 }
00429
00430 if ((listener->get_tcp_state() == TcpStreamTracker::TCP_ESTABLISHED)
00431 && (listener->flush_policy == STREAM_FLPOLICY_IGNORE))
00432 {
00433 if (SEQ_GT(tsd.get_end_seq(), listener->r_nxt_ack))
00434 {
00435 // set next ack so we are within the window going forward on this side.
00436 // FIXIT-L for ips, must move all the way to first hole or right end
00437 listener->r_nxt_ack = tsd.get_end_seq();
00438 }
00439 }
00440
00441 if (tsd.get_seg_len() != 0)
00442 {
00443 if (!( flow->get_session_flags() & SSNFLAG_STREAM_ORDER_BAD))
00444 {
00445 if (!SEQ_LEQ((tsd.get_seg_seq() + tsd.get_seg_len()), listener->r_nxt_ack))
00446 flow->set_session_flags(SSNFLAG_STREAM_ORDER_BAD);
00447 }
00448 process_tcp_stream(tsd);
00449 }
00450 }
00451
00452 return STREAM_UNALIGNED;
00453 }
00454
00455 void TcpSession::set_os_policy()
00456 {
00457 StreamPolicy client_os_policy = flow->ssn_policy ?
00458 static_cast<StreamPolicy>( flow->ssn_policy ) : config->policy;
00459 StreamPolicy server_os_policy = flow->ssn_policy ?
00460 static_cast<StreamPolicy>( flow->ssn_policy ) : config->policy;
00461
00462 if ( client->normalizer == nullptr )
00463 client->normalizer = TcpNormalizerFactory::create(this, client_os_policy, client, server);
00464
00465 if ( server->normalizer == nullptr )
00466 server->normalizer = TcpNormalizerFactory::create(this, server_os_policy, server, client);
00467
00468 if ( client->reassembler == nullptr )
00469 client->reassembler = TcpReassemblerFactory::create(this, client, client_os_policy, false);
00470
00471 if ( server->reassembler == nullptr )
00472 server->reassembler = TcpReassemblerFactory::create(this, server, server_os_policy, true);
00473 }
00474
00475 // FIXIT-H this is no longer called (but should be)
00476 void TcpSession::swap_trackers()
00477 {
00478 uint32_t session_flags = flow->get_session_flags( );
00479 if ( ( session_flags & SSNFLAG_CLIENT_SWAP ) && !( session_flags & SSNFLAG_CLIENT_SWAPPED ) )
00480 {
00481 TcpStreamTracker* trk = client;
00482 client = server;
00483 server = trk;
00484
00485 SfIp ip = flow->client_ip;
00486 flow->client_ip = flow->server_ip;
00487 flow->server_ip = ip;
00488
00489 uint16_t port = flow->client_port;
00490 flow->client_port = flow->server_port;
00491 flow->server_port = port;
00492
00493 if ( !flow->two_way_traffic() )
00494 {
00495 if ( session_flags & SSNFLAG_SEEN_CLIENT )
00496 {
00497 session_flags ^= SSNFLAG_SEEN_CLIENT;
00498 session_flags |= SSNFLAG_SEEN_SERVER;
00499 }
00500 else if ( session_flags & SSNFLAG_SEEN_SERVER )
00501 {
00502 session_flags ^= SSNFLAG_SEEN_SERVER;
00503 session_flags |= SSNFLAG_SEEN_CLIENT;
00504 }
00505 }
00506
00507 session_flags |= SSNFLAG_CLIENT_SWAPPED;
00508 flow->update_session_flags(session_flags);
00509 }
00510 }
00511
00512 void TcpSession::NewTcpSessionOnSyn(TcpSegmentDescriptor& tsd)
00513 {
00514 server->init_on_syn_recv(tsd);
00515 client->init_on_syn_sent(tsd);
00516 init_new_tcp_session(tsd);
00517 tcpStats.sessions_on_syn++;
00518 }
00519
00520 void TcpSession::NewTcpSessionOnSynAck(TcpSegmentDescriptor& tsd)
00521 {
00522 server->init_on_synack_sent(tsd);
00523 client->init_on_synack_recv(tsd);
00524 init_new_tcp_session(tsd);
00525 tcpStats.sessions_on_syn_ack++;
00526 }
00527
00528 void TcpSession::update_timestamp_tracking(TcpSegmentDescriptor& tsd)
00529 {
00530 talker->set_tf_flags(listener->normalizer->get_timestamp_flags());
00531 if (listener->normalizer->handling_timestamps()
00532 && SEQ_EQ(listener->r_nxt_ack, tsd.get_seg_seq()))
00533 {
00534 talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec);
00535 talker->set_ts_last(tsd.get_ts());
00536 }
00537 }
00538
00539 bool TcpSession::handle_syn_on_reset_session(TcpSegmentDescriptor& tsd)
00540 {
00541 const tcp::TCPHdr* tcph = tsd.get_tcph();
00542 if ( ( listener->get_tcp_state() == TcpStreamTracker::TCP_CLOSED )
00543 || ( talker->get_tcp_state() == TcpStreamTracker::TCP_CLOSED ) )
00544 {
00545 // Listener previously issued a reset Talker is re-SYN-ing
00546 DebugMessage(DEBUG_STREAM_STATE, "Got SYN pkt on reset ssn, re-SYN-ing\n");
00547
00548 // FIXIT-M this leads to bogus 129:20
00549 clear_session( true, true, true, tsd.get_pkt() );
00550
00551 if ( tcph->is_rst() )
00552 {
00553 // FIXIT-M In inline mode, only one of the normalizations can
00554 // occur. If the first normalization fires, there is nothing
00555 // for the second normalization to do. However, in inline-test
00556 // mode, since nothing is actually normalized, both of the
00557 // following functions report that they 'would' normalize.
00558 // i.e., both functions increment their count even though only
00559 // one function can ever perform a normalization.
00560
00561 /* Got SYN/RST. We're done. */
00562 listener->normalizer->trim_syn_payload(tsd);
00563 listener->normalizer->trim_rst_payload(tsd);
00564 pkt_action_mask |= ACTION_RST;
00565 return false;
00566 }
00567 else if (tcph->is_syn_only())
00568 {
00569 flow->ssn_state.direction = FROM_CLIENT;
00570 flow->session_state = STREAM_STATE_SYN;
00571 flow->set_ttl(tsd.get_pkt(), true);
00572 NewTcpSessionOnSyn(tsd);
00573 tcpStats.resyns++;
00574 listener = server;
00575 talker = client;
00576 listener->normalizer->ecn_tracker( tcph, config->require_3whs() );
00577 flow->update_session_flags(SSNFLAG_SEEN_CLIENT);
00578 }
00579 else if (tcph->is_syn_ack())
00580 {
00581 if (config->midstream_allowed(tsd.get_pkt()))
00582 {
00583 flow->ssn_state.direction = FROM_SERVER;
00584 flow->session_state = STREAM_STATE_SYN_ACK;
00585 flow->set_ttl(tsd.get_pkt(), false);
00586 NewTcpSessionOnSynAck(tsd);
00587 tcpStats.resyns++;
00588 }
00589
00590 listener = client;
00591 talker = server;
00592 listener->normalizer->ecn_tracker( tcph, config->require_3whs() );
00593 flow->update_session_flags(SSNFLAG_SEEN_SERVER);
00594 }
00595 }
00596
00597 return true;
00598 }
00599
00600 void TcpSession::update_ignored_session(TcpSegmentDescriptor& tsd)
00601 {
00602 // FIXIT-L why flush here instead of just purge?
00603 // s5_ignored_session() may be disabling detection too soon if we really want to flush
00604 if (Stream::ignored_flow(flow, tsd.get_pkt()))
00605 {
00606 if ( talker && ( talker->get_tf_flags() & TF_FORCE_FLUSH ) )
00607 {
00608 flush_talker(tsd.get_pkt() );
00609 talker->clear_tf_flags(TF_FORCE_FLUSH);
00610 }
00611
00612 if ( listener && ( listener->get_tf_flags() & TF_FORCE_FLUSH ) )
00613 {
00614 flush_listener(tsd.get_pkt());
00615 listener->clear_tf_flags(TF_FORCE_FLUSH);
00616 }
00617
00618 tsd.get_pkt()->packet_flags |= PKT_IGNORE;
00619 pkt_action_mask |= ACTION_DISABLE_INSPECTION;
00620 }
00621 }
00622
00623 void TcpSession::handle_data_on_syn(TcpSegmentDescriptor& tsd)
00624 {
00625 /* MacOS accepts data on SYN, so don't alert if policy is MACOS */
00626 if (talker->normalizer->get_os_policy() == StreamPolicy::OS_MACOS)
00627 {
00628 handle_data_segment(tsd);
00629 }
00630 else
00631 {
00632 // remove data on SYN
00633 listener->normalizer->trim_syn_payload(tsd);
00634
00635 if (Normalize_GetMode(NORM_TCP_TRIM_SYN) != NORM_MODE_ON)
00636 {
00637 DebugMessage(DEBUG_STREAM_STATE, "Got data on SYN packet, not processing it\n");
00638 tel.set_tcp_event(EVENT_DATA_ON_SYN);
00639 pkt_action_mask |= ACTION_BAD_PKT;
00640 }
00641 }
00642 }
00643
00644 void TcpSession::update_session_on_rst(TcpSegmentDescriptor& tsd, bool flush)
00645 {
00646 if ( flush )
00647 {
00648 DetectionEngine::onload(flow);
00649 flush_listener(tsd.get_pkt(), true);
00650 flush_talker(tsd.get_pkt(), true);
00651 DetectionEngine::onload(flow); // FIXIT-H don't allow offload above
00652 set_splitter(true, nullptr);
00653 set_splitter(false, nullptr);
00654 flow->free_flow_data();
00655 }
00656
00657 talker->update_on_rst_sent( );
00658 }
00659
00660 void TcpSession::update_paws_timestamps(TcpSegmentDescriptor& tsd)
00661 {
00662 // update PAWS timestamps
00663 DebugFormat(DEBUG_STREAM_STATE, "PAWS update tsd.seq %u > listener->r_win_base %u\n",
00664 tsd.get_seg_seq(), listener->r_win_base);
00665
00666 if ( listener->normalizer->handling_timestamps()
00667 && SEQ_EQ(listener->r_win_base, tsd.get_seg_seq() ) )
00668 {
00669 if ( ( (int32_t)(tsd.get_ts() - talker->get_ts_last() ) >= 0 )
00670 ||
00671 ( ( uint32_t )tsd.get_pkt()->pkth->ts.tv_sec
00672 >= talker->get_ts_last_packet() + PAWS_24DAYS ) )
00673 {
00674 DebugMessage(DEBUG_STREAM_STATE, "updating timestamps...\n");
00675 talker->set_ts_last(tsd.get_ts());
00676 talker->set_ts_last_packet(tsd.get_pkt()->pkth->ts.tv_sec);
00677 }
00678 }
00679 else
00680 {
00681 DebugMessage(DEBUG_STREAM_STATE, "not updating timestamps...\n");
00682 }
00683 }
00684
00685 void TcpSession::check_for_session_hijack(TcpSegmentDescriptor& tsd)
00686 {
00687 if (!(tsd.get_pkt()->pkth->flags & DAQ_PKT_FLAG_PRE_ROUTING))
00688 {
00689 uint32_t event_code = 0;
00690
00691 if ( tsd.get_pkt()->is_eth() )
00692 {
00693 // if flag is set, guaranteed to have an eth layer
00694 Packet* p = tsd.get_pkt();
00695 const eth::EtherHdr* eh = layer::get_eth_layer(p);
00696 bool t_hijack = !talker->compare_mac_addresses(eh->ether_src);
00697 bool l_hijack = !listener->compare_mac_addresses(eh->ether_dst);
00698
00699 // if both seem hijacked then swap src/dst check, it that matches probably a tap
00700 if ( ( t_hijack & l_hijack ) &&
00701 ( talker->compare_mac_addresses(eh->ether_dst) &&
00702 listener->compare_mac_addresses(eh->ether_src) ) )
00703 return;
00704
00705 if ( t_hijack )
00706 {
00707 if ( p->is_from_client() )
00708 event_code |= EVENT_SESSION_HIJACK_CLIENT;
00709 else
00710 event_code |= EVENT_SESSION_HIJACK_SERVER;
00711 }
00712
00713 if ( l_hijack )
00714 {
00715 if ( p->is_from_client() )
00716 event_code |= EVENT_SESSION_HIJACK_SERVER;
00717 else
00718 event_code |= EVENT_SESSION_HIJACK_CLIENT;
00719 }
00720
00721 if (event_code)
00722 tel.set_tcp_event(event_code);
00723 }
00724 }
00725 }
00726
00727 bool TcpSession::check_for_window_slam(TcpSegmentDescriptor& tsd)
00728 {
00729 if ( config->max_window && (tsd.get_seg_wnd() > config->max_window ) )
00730 {
00731 DebugMessage(DEBUG_STREAM_STATE,
00732 "Got window that was beyond the allowed policy value, bailing\n");
00733 /* got a window too large, alert! */
00734 tel.set_tcp_event(EVENT_WINDOW_TOO_LARGE);
00735 inc_tcp_discards();
00736 listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK);
00737 pkt_action_mask |= ACTION_BAD_PKT;
00738 return true;
00739 }
00740 else if ((tsd.get_pkt()->is_from_client())
00741 && (tsd.get_seg_wnd() <= SLAM_MAX)
00742 && (tsd.get_seg_ack() == listener->get_iss() + 1)
00743 && !( tsd.get_tcph()->is_fin() | tsd.get_tcph()->is_rst() )
00744 && !(flow->get_session_flags() & SSNFLAG_MIDSTREAM))
00745 {
00746 DebugMessage(DEBUG_STREAM_STATE, "Window slammed shut!\n");
00747 /* got a window slam alert! */
00748 tel.set_tcp_event(EVENT_WINDOW_SLAM);
00749 inc_tcp_discards();
00750
00751 if (listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK))
00752 {
00753 pkt_action_mask |= ACTION_BAD_PKT;
00754 return true;
00755 }
00756 }
00757
00758 return false;
00759 }
00760
00761 void TcpSession::mark_packet_for_drop(TcpSegmentDescriptor& tsd)
00762 {
00763 listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK);
00764 set_pkt_action_flag(ACTION_BAD_PKT);
00765 }
00766
00767 void TcpSession::handle_data_segment(TcpSegmentDescriptor& tsd)
00768 {
00769 DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d) getting data\n",
00770 l_name, tcp_state_names[listener->get_tcp_state()], listener->get_tcp_state());
00771
00772 DebugFormat(DEBUG_STREAM_STATE, "Queuing data on listener, t %s, l %s...\n",
00773 flush_policy_names[talker->flush_policy],
00774 flush_policy_names[listener->flush_policy]);
00775
00776 if ( TcpStreamTracker::TCP_CLOSED != talker->get_tcp_state() )
00777 {
00778 // FIXIT-M move this to normalizer base class, handle OS_PROXY in derived class
00779 if (config->policy != StreamPolicy::OS_PROXY)
00780 {
00781 /* check for valid sequence/retrans */
00782 if (!listener->is_segment_seq_valid(tsd) )
00783 return;
00784
00785 // these normalizations can't be done if we missed setup. and
00786 // window is zero in one direction until we've seen both sides.
00787 if (!(flow->get_session_flags() & SSNFLAG_MIDSTREAM) && flow->two_way_traffic())
00788 {
00789 // sender of syn w/mss limits payloads from peer since we store mss on
00790 // sender side, use listener mss same reasoning for window size
00791 TcpStreamTracker* st = listener;
00792
00793 // trim to fit in window and mss as needed
00794 st->normalizer->trim_win_payload(tsd, (st->r_win_base + st->get_snd_wnd() -
00795 st->r_nxt_ack));
00796
00797 if (st->get_mss())
00798 st->normalizer->trim_mss_payload(tsd, st->get_mss());
00799
00800 st->normalizer->ecn_stripper(tsd.get_pkt());
00801 }
00802 }
00803
00804 // dunno if this is RFC but fragroute testing expects it for the record,
00805 // I've seen FTP data sessions that send data packets with no tcp flags set
00806 if ((tsd.get_tcph()->th_flags != 0) or (config->policy == StreamPolicy::OS_LINUX)
00807 or (config->policy == StreamPolicy::OS_PROXY))
00808 {
00809 process_tcp_data(tsd);
00810 //Check if all segments are received. Process FIN transition
00811 check_fin_transition_status(tsd);
00812 }
00813 else
00814 {
00815 tel.set_tcp_event(EVENT_DATA_WITHOUT_FLAGS);
00816 listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK);
00817 }
00818 }
00819
00820 listener->reassembler->flush_on_data_policy(tsd.get_pkt());
00821 }
00822
00823 TcpStreamTracker::TcpState TcpSession::get_talker_state()
00824 {
00825 return talker->get_tcp_state();
00826 }
00827
00828 TcpStreamTracker::TcpState TcpSession::get_listener_state()
00829 {
00830 return listener->get_tcp_state();
00831 }
00832
00833 void TcpSession::check_for_repeated_syn(TcpSegmentDescriptor& tsd)
00834 {
00835 uint32_t action = ACTION_NOTHING;
00836
00837 if ( !SEQ_EQ(tsd.get_seg_seq(), talker->get_iss()) and
00838 listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK) )
00839 {
00840 action = ACTION_BAD_PKT;
00841 }
00842 else if ( talker->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED and
00843 talker->get_tcp_state() < TcpStreamTracker::TCP_CLOSED )
00844 {
00845 action = listener->normalizer->handle_repeated_syn(tsd);
00846 }
00847 if (action != ACTION_NOTHING)
00848 {
00849 /* got a bad SYN on the session, alert! */
00850 tel.set_tcp_event(EVENT_SYN_ON_EST);
00851 pkt_action_mask |= action;
00852 }
00853 }
00854
00855 void TcpSession::flush_server(Packet* p)
00856 {
00857 server->set_tf_flags(TF_FORCE_FLUSH);
00858
00859 // If rebuilt packet, don't flush now because we'll overwrite the packet being processed.
00860 if ( p->packet_flags & PKT_REBUILT_STREAM )
00861 {
00862 // We'll check & clear the TF_FORCE_FLUSH next time through
00863 return;
00864 }
00865
00866 // Need to convert the addresses to network order
00867 if ( server->reassembler->flush_stream(p, PKT_FROM_SERVER) )
00868 server->reassembler->purge_flushed_ackd( );
00869
00870 server->clear_tf_flags(TF_FORCE_FLUSH);
00871 }
00872
00873 void TcpSession::flush_client(Packet* p)
00874 {
00875 client->set_tf_flags(TF_FORCE_FLUSH);
00876
00877 // If rebuilt packet, don't flush now because we'll overwrite the packet being processed.
00878 if ( p->packet_flags & PKT_REBUILT_STREAM )
00879 {
00880 // We'll check & clear the TF_FORCE_FLUSH next time through
00881 return;
00882 }
00883
00884 if ( client->reassembler->flush_stream(p, PKT_FROM_CLIENT) )
00885 client->reassembler->purge_flushed_ackd( );
00886
00887 client->clear_tf_flags(TF_FORCE_FLUSH);
00888 }
00889
00890 void TcpSession::flush_tracker(TcpStreamTracker* tracker, Packet* p, uint32_t dir, bool final_flush)
00891 {
00892 if( final_flush && ( !tracker->splitter || !tracker->splitter->finish(flow) ) )
00893 return;
00894
00895 DebugFormat(DEBUG_STREAM_STATE, "Flushing tracker on packet from %s\n",
00896 (dir == PKT_FROM_CLIENT) ? "client" : "server");
00897 tracker->set_tf_flags(TF_FORCE_FLUSH);
00898 if ( tracker->reassembler->flush_stream(p, dir) )
00899 tracker->reassembler->purge_flushed_ackd( );
00900
00901 tracker->clear_tf_flags(TF_FORCE_FLUSH);
00902 }
00903
00904 void TcpSession::flush_listener(Packet* p, bool final_flush)
00905 {
00906 // direction of flush is the data from the opposite side
00907 if ( p->is_from_server() )
00908 flush_tracker( client, p, PKT_FROM_SERVER, final_flush);
00909 else if ( p->is_from_client() )
00910 flush_tracker( server, p, PKT_FROM_CLIENT, final_flush);
00911 }
00912
00913 void TcpSession::flush_talker(Packet* p, bool final_flush)
00914 {
00915 // direction of flush is the data from the opposite side
00916 if ( p->is_from_server() )
00917 flush_tracker( server, p, PKT_FROM_CLIENT, final_flush);
00918 else if ( p->is_from_client() )
00919 flush_tracker( client, p, PKT_FROM_SERVER, final_flush);
00920 }
00921
00922 void TcpSession::set_extra_data(Packet* p, uint32_t xid)
00923 {
00924 TcpStreamTracker* st;
00925
00926 if (p->ptrs.ip_api.get_src()->equals(flow->client_ip))
00927 st = server;
00928 else
00929 st = client;
00930
00931 st->reassembler->set_xtradata_mask(st->reassembler->get_xtradata_mask() | BIT(xid) );
00932 }
00933
00934 static inline void set_window_scale(TcpStreamTracker& talker, TcpStreamTracker& listener,
00935 TcpSegmentDescriptor& tsd)
00936 {
00937 // scale the window. Only if BOTH client and server specified wscale option as part
00938 // of 3-way handshake. This is per RFC 1323.
00939 if ( ( talker.get_tf_flags() & TF_WSCALE ) && ( listener.get_tf_flags() & TF_WSCALE ) )
00940 tsd.scale_seg_wnd(talker.get_wscale() );
00941 }
00942
00943 void TcpSession::do_packet_analysis_post_checks(Packet* p)
00944 {
00945 tel.log_tcp_events();
00946
00947 if (!(pkt_action_mask & ACTION_LWSSN_CLOSED))
00948 {
00949 flow->markup_packet_flags(p);
00950 flow->set_expire(p, config->session_timeout);
00951 }
00952 else
00953 TcpHAManager::process_deletion(p->flow);
00954
00955 if (pkt_action_mask & ACTION_DISABLE_INSPECTION)
00956 {
00957 DetectionEngine::disable_all(p);
00958
00959 DebugFormat(DEBUG_STREAM_STATE,
00960 "Stream Ignoring packet from %s. Session marked as ignore\n",
00961 p->is_from_server() ? "server" : "client");
00962 }
00963 }
00964
00965 // FIXIT-M can flow do these checks before calling stream tcp?
00966 bool TcpSession::is_flow_handling_packets(Packet* p)
00967 {
00968 bool flow_ready = true;
00969
00970 // FIXIT-L can't get here without protocol being set to TCP, is this really needed??
00971 if (flow->pkt_type != PktType::TCP)
00972 {
00973 DebugMessage(DEBUG_STREAM_STATE, "Lightweight session not TCP on TCP packet\n");
00974 return false;
00975 }
00976
00977 if(flow->session_state & STREAM_STATE_IGNORE)
00978 {
00979 tcpStats.ignored++;
00980 flow_ready = false;
00981 }
00982 else
00983 flow_ready = !Stream::blocked_flow(flow, p);
00984
00985 // FIXIT-L expected flow should be checked by Stream before we get here
00986 // harmonize this with that and the checks above
00987 if ( Stream::expected_flow(flow, p) )
00988 {
00989 server->flush_policy = STREAM_FLPOLICY_IGNORE;
00990 client->flush_policy = STREAM_FLPOLICY_IGNORE;
00991 flow_ready = false;
00992 }
00993
00994 return flow_ready;
00995 }
00996
00997 void TcpSession::cleanup_session_if_expired(Packet* p)
00998 {
00999 // Check if the session is expired. Should be done before we do something with
01000 // the packet...Insert a packet, or handle state change SYN, FIN, RST, etc.
01001 if (Stream::expired_flow(flow, p))
01002 {
01003 /* Session is timed out, if also reset then restart, otherwise clear */
01004 if (flow->get_session_flags() & SSNFLAG_RESET)
01005 clear_session(true, true, true, p);
01006 else
01007 clear_session(true, true, false, p);
01008
01009 tcpStats.timeouts++;
01010 TcpHAManager::process_deletion(flow);
01011 }
01012 }
01013
01014 void TcpSession::precheck(Packet* p)
01015 {
01016 // Check if the session is expired. Should be done before we do something with
01017 // the packet...Insert a packet, or handle state change SYN, FIN, RST, etc.
01018 cleanup_session_if_expired(p);
01019 }
01020
01021 bool TcpSession::do_packet_analysis_pre_checks(Packet* p, TcpSegmentDescriptor& tsd)
01022 {
01023 if ( !is_flow_handling_packets(p) )
01024 return false;
01025
01026 pkt_action_mask = ACTION_NOTHING;
01027 tel.clear_tcp_events();
01028 // process thru state machine...talker first
01029 if (p->is_from_client())
01030 {
01031 update_session_on_client_packet(tsd);
01032 DEBUG_WRAP(t_name = "Server"; l_name = "Client");
01033 }
01034 else
01035 {
01036 update_session_on_server_packet(tsd);
01037 DEBUG_WRAP(t_name = "Server"; l_name = "Client");
01038 }
01039
01040 update_ignored_session(tsd);
01041 set_window_scale(*talker, *listener, tsd);
01042 check_for_session_hijack(tsd);
01043
01044 DebugFormat(DEBUG_STREAM_STATE, " %s [talker] state: %s\n", t_name,
01045 tcp_state_names[talker->get_tcp_state()]);
01046 DebugFormat(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l_name,
01047 tcp_state_names[listener->get_tcp_state()], listener->get_tcp_state());
01048
01049 return true;
01050 }
01051
01052 bool TcpSession::validate_packet_established_session(TcpSegmentDescriptor& tsd)
01053 {
01054 pkt_action_mask |= listener->normalizer->handle_paws(tsd);
01055
01056 if ( pkt_action_mask & ACTION_BAD_PKT )
01057 return false;
01058
01059 return true;
01060 }
01061
01062 /*
01063 * Main entry point for TCP
01064 */
01065 int TcpSession::process(Packet* p)
01066 {
01067 Profile profile(s5TcpPerfStats);
01068
01069 DEBUG_WRAP
01070 (
01071 char flagbuf[9];
01072 CreateTCPFlagString(p->ptrs.tcph, flagbuf);
01073
01074 char src_addr[INET6_ADDRSTRLEN];
01075 char dst_addr[INET6_ADDRSTRLEN];
01076
01077 sfip_ntop(p->ptrs.ip_api.get_src(), src_addr, sizeof(src_addr));
01078 sfip_ntop(p->ptrs.ip_api.get_dst(), dst_addr, sizeof(dst_addr));
01079
01080 DebugFormat((DEBUG_STREAM|DEBUG_STREAM_STATE),
01081 "Got TCP Packet %s:%hu -> %s:%hu %s\nseq: 0x%X ack:0x%X dsize: %hu\n",
01082 src_addr, p->ptrs.sp, dst_addr, p->ptrs.dp, flagbuf,
01083 p->ptrs.tcph->seq(), p->ptrs.tcph->ack(), p->dsize);
01084 );
01085
01086 assert(flow->ssn_server);
01087
01088 // FIXIT-H need to do something here to handle check for need to swap trackers??
01089 if ( !config )
01090 config = get_tcp_cfg(flow->ssn_server);
01091
01092 if( !tcp_init )
01093 set_os_policy( );
01094
01095 TcpSegmentDescriptor tsd(flow, p, tel);
01096
01097 if ( !do_packet_analysis_pre_checks(p, tsd) )
01098 return ACTION_NOTHING;
01099
01100 if ( ( flow->get_session_flags() & SSNFLAG_RESET ) && tsd.get_tcph()->is_syn()
01101 && !handle_syn_on_reset_session(tsd) )
01102 return ACTION_NOTHING;
01103 else
01104 {
01105 Profile profile(s5TcpStatePerfStats);
01106
01107 if ( tsm->eval(tsd, *talker, *listener) )
01108 {
01109 do_packet_analysis_post_checks(p);
01110 S5TraceTCP(p, flow, &tsd, 0);
01111 }
01112 else
01113 {
01114 if ( pkt_action_mask & ACTION_BAD_PKT )
01115 {
01116 DebugMessage(DEBUG_STREAM_STATE, "bad packet, bailing\n");
01117 inc_tcp_discards();
01118
01119 do_packet_analysis_post_checks(p);
01120 }
01121
01122 tel.log_tcp_events();
01123 S5TraceTCP(p, flow, &tsd, 0);
01124 }
01125 }
01126
01127 DebugMessage(DEBUG_STREAM_STATE,
01128 "Finished Stream TCP cleanly!\n---------------------------------------------------\n");
01129
01130 return ACTION_NOTHING;
01131 }
01132
01133 void TcpSession::flush()
01134 {
01135 if ( ( server->reassembler->is_segment_pending_flush() ) ||
01136 (client->reassembler->is_segment_pending_flush() ) )
01137 {
01138 // FIXIT-L flush_queued_segments is basically a noop when the 'clear' parameter
01139 // is passed in as false... review what happens in 2.9.x probably related
01140 // to ssl encryption support
01141 server->reassembler->flush_queued_segments(flow, false);
01142 client->reassembler->flush_queued_segments(flow, false);
01143 }
01144 }
01145
END OF CODE