stream_base
stream_ip
stream_icmp
- stream_libtcp
stream_tcp
+ stream_libtcp
stream_udp
stream_user
stream_file
stream/base/libstream_base.a \
stream/ip/libstream_ip.a \
stream/icmp/libstream_icmp.a \
-stream/libtcp/libstream_libtcp.a \
stream/tcp/libstream_tcp.a \
+stream/libtcp/libstream_libtcp.a \
stream/udp/libstream_udp.a \
stream/user/libstream_user.a \
stream/file/libstream_file.a \
inline bool is_rst() const
{ return (th_flags & TH_RST); }
+ inline bool is_fin() const
+ { return (th_flags & TH_FIN); }
+
/* raw data access */
inline uint16_t raw_src_port() const
{ return th_sport; }
add_library( stream_libtcp STATIC
- tcp_stream_tracker.cc
+ tcp_segment_descriptor.cc
+ tcp_stream_tracker.cc
tcp_state_handler.cc
tcp_state_machine.cc
+ stream_tcp_unit_test.cc
)
tcp_state_handler.cc \
tcp_state_handler.h \
tcp_state_machine.cc \
-tcp_state_machine.h
+tcp_state_machine.h \
+tcp_segment_descriptor.cc \
+tcp_segment_descriptor.h \
+stream_tcp_unit_test.cc
--- /dev/null
+This directory contains the implementation of common TCP session tracking functions.
+
+This TCP library module provides the following functions:
+
+* TCP Segment Descriptor - this class provides access to the various fields of the TCP
+ header and payload
+
+* TCP Stream Tracker - this class encapsulates all the state information required for
+ tracking one side of the TCP connection. For each flow that is tracked there will be
+ two instances of this tracker, one for each direction.
+
+* TCP State Handler - abstract class interface that defines a method for handling each
+ possible TCP event. For each TCP state a subclass of this class is created with a
+ state specific implementation for each event handling method.
+
+* TCP State Machine - this class is the engine that dispatches processing to the correct
+ event handling method of the handler for the current TCP state of the flow.
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// stream_libtcp_unit_test.h author davis mcpherson <davmcphe@@cisco.com>
+// Created on: Jul 30, 2015
+
+#ifndef STREAM_LIBTCP_UNIT_TEST
+#define STREAM_LIBTCP_UNIT_TEST
+
+#include <stdint.h>
+
+#include "protocols/packet.h"
+#include "protocols/tcp.h"
+#include "stream_tcp_unit_test.h"
+
+// SYN PACKET
+// IP 192.168.0.89.9012 > p3nlh044.shr.prod.phx3.secureserver.net.http: Flags [S], seq 9050, win 8192, length 0
+ uint8_t cooked_syn[] = "\x00\x21\x91\x01\xb2\x48\xaa\x00\x04\x00\x0a\x04\x08\x00\x45\x00\x00\x28\x00\x01\x00\x00\x40\x06\x88\x96\xc0\xa8\x00\x59\x48\xa7\xe8\x90\x23\x34\x00\x50\x00\x00\x23\x5a\x00\x00\x00\x00\x50\x02\x20\x00\x56\xcb\x00\x00";
+
+// SYN-ACK PACKET
+// IP p3nlh044.shr.prod.phx3.secureserver.net.http > 192.168.0.89.9012: Flags [S.], seq 9025, ack 9051, win 8192, length 0
+ uint8_t cooked_syn_ack[] = "\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x08\x00\x45\x00\x00\x28\x00\x01\x00\x00\x40\x06\x88\x96\x48\xa7\xe8\x90\xc0\xa8\x00\x59\x00\x50\x23\x34\x00\x00\x23\x41\x00\x00\x23\x5b\x50\x12\x20\x00\x33\x79\x00\x00";
+
+// ACK PACKET
+// IP 192.168.0.89.9012 > p3nlh044.shr.prod.phx3.secureserver.net.http: Flags [.], ack 1, win 8192, length 0
+ uint8_t cooked_ack[] = "\x00\x21\x91\x01\xb2\x48\xaa\x00\x04\x00\x0a\x04\x08\x00\x45\x00\x00\x28\x00\x01\x00\x00\x40\x06\x88\x96\xc0\xa8\x00\x59\x48\xa7\xe8\x90\x23\x34\x00\x50\x00\x00\x23\x5b\x00\x00\x23\x42\x50\x10\x20\x00\x33\x7a\x00\x00";
+
+// FIXIT - this is not a FIN PACKET yet...
+// IP 192.168.0.89.9012 > p3nlh044.shr.prod.phx3.secureserver.net.http: Flags [.], ack 1, win 8192, length 0
+ uint8_t cooked_fin[] = "\x00\x21\x91\x01\xb2\x48\xaa\x00\x04\x00\x0a\x04\x08\x00\x45\x00\x00\x28\x00\x01\x00\x00\x40\x06\x88\x96\xc0\xa8\x00\x59\x48\xa7\xe8\x90\x23\x34\x00\x50\x00\x00\x23\x5b\x00\x00\x23\x42\x50\x10\x20\x00\x33\x7a\x00\x00";
+
+// FIXIT - this is not a RST PACKET yet...
+// IP 192.168.0.89.9012 > p3nlh044.shr.prod.phx3.secureserver.net.http: Flags [.], ack 1, win 8192, length 0
+ uint8_t cooked_rst[] = "\x00\x21\x91\x01\xb2\x48\xaa\x00\x04\x00\x0a\x04\x08\x00\x45\x00\x00\x28\x00\x01\x00\x00\x40\x06\x88\x96\xc0\xa8\x00\x59\x48\xa7\xe8\x90\x23\x34\x00\x50\x00\x00\x23\x5b\x00\x00\x23\x42\x50\x10\x20\x00\x33\x7a\x00\x00";
+
+// DATA PACKET
+// IP 192.168.0.89.9012 > p3nlh044.shr.prod.phx3.secureserver.net.http: Flags [P.], seq 1:43, ack 1, win 8192, length 42
+ uint8_t cooked_data[] = "\x00\x21\x91\x01\xb2\x48\xaa\x00\x04\x00\x0a\x04\x08\x00\x45\x00\x00\x52\x00\x01\x00\x00\x40\x06\x88\x6c\xc0\xa8\x00\x59\x48\xa7\xe8\x90\x23\x34\x00\x50\x00\x00\x23\x5b\x00\x00\x23\x42\x50\x18\x20\x00\x14\x83\x00\x00\x47\x45\x54\x20\x2f\x20\x48\x54\x54\x50\x2f\x31\x2e\x31\x0d\x0a\x48\x6f\x73\x74\x3a\x20\x77\x77\x77\x2e\x6d\x61\x6c\x66\x6f\x72\x67\x65\x2e\x63\x6f\x6d\x0d\x0a\x0d\x0a";
+
+
+Packet *get_syn_packet( Flow* flow )
+{
+ Packet* pkt = new Packet;
+
+ pkt->flow = flow;
+ pkt->pkt = cooked_syn;
+ pkt->ptrs.tcph = ( tcp::TCPHdr * ) ( cooked_syn + 34 );
+ pkt->dsize = 0;
+ pkt->packet_flags &= PKT_FROM_CLIENT;
+ return pkt;
+
+}
+
+Packet *get_syn_ack_packet( Flow* flow )
+{
+ Packet* pkt = new Packet;
+
+ pkt->flow = flow;
+ pkt->pkt = cooked_syn_ack;
+ pkt->ptrs.tcph = ( tcp::TCPHdr * ) ( cooked_syn_ack + 34 );
+ pkt->dsize = 0;
+ pkt->packet_flags &= PKT_FROM_SERVER;
+ return pkt;
+
+}
+
+Packet *get_ack_packet( Flow* flow )
+{
+ Packet* pkt = new Packet;
+
+ pkt->flow = flow;
+ pkt->pkt = cooked_ack;
+ pkt->ptrs.tcph = ( tcp::TCPHdr * ) ( cooked_ack + 34 );
+ pkt->dsize = 0;
+ pkt->packet_flags &= PKT_FROM_CLIENT;
+ return pkt;
+
+}
+
+Packet *get_fin_packet( Flow* flow )
+{
+ Packet* pkt = new Packet;
+
+ pkt->flow = flow;
+ pkt->pkt = cooked_fin;
+ pkt->ptrs.tcph = ( tcp::TCPHdr * ) ( cooked_fin + 34 );
+ pkt->dsize = 0;
+ pkt->packet_flags &= PKT_FROM_CLIENT;
+ return pkt;
+
+}
+
+Packet *get_rst_packet( Flow* flow )
+{
+ Packet* pkt = new Packet;
+
+ pkt->flow = flow;
+ pkt->pkt = cooked_rst;
+ pkt->ptrs.tcph = ( tcp::TCPHdr * ) ( cooked_rst + 34 );
+ pkt->dsize = 0;
+ pkt->packet_flags &= PKT_FROM_CLIENT;
+ return pkt;
+
+}
+
+Packet *get_data_packet( Flow* flow )
+{
+ Packet* pkt = new Packet;
+
+ pkt->flow = flow;
+ pkt->pkt = cooked_data;
+ pkt->ptrs.tcph = ( tcp::TCPHdr * ) ( cooked_data + 34 );
+ pkt->dsize = 42;
+ pkt->packet_flags &= PKT_FROM_CLIENT;
+ return pkt;
+
+}
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// stream_libtcp_unit_test.h author davis mcpherson <davmcphe@@cisco.com>
+// Created on: Jul 30, 2015
+
+#ifndef STREAM_LIBTCP_UNIT_TEST
+#define STREAM_LIBTCP_UNIT_TEST
+
+#include <stdint.h>
+
+#include "protocols/packet.h"
+
+Packet *get_syn_packet( Flow* flow );
+Packet *get_syn_ack_packet( Flow* flow );
+Packet *get_ack_packet( Flow* flow );
+Packet *get_fin_packet( Flow* flow );
+Packet *get_rst_packet( Flow* flow );
+Packet *get_data_packet( Flow* flow );
+
+#endif
+
#include "tcp_segment_descriptor.h"
-TcpSegmentDescriptor::TcpSegmentDescriptor( Flow* flow, Packet* pkt )
+TcpSegmentDescriptor::TcpSegmentDescriptor( Flow* flow, Packet* pkt ) :
+ flow( flow )
{
- // TODO Auto-generated constructor stub
+ direction = flow->ssn_state.direction;
+
+ tcph = pkt->ptrs.tcph;
+ data_len = pkt->dsize;
+
+#if 1
+ src_port = ntohs(tcph->th_sport);
+ dst_port = ntohs(pkt->ptrs.tcph->th_dport);
+ seq = ntohl(pkt->ptrs.tcph->th_seq);
+ ack = ntohl(pkt->ptrs.tcph->th_ack);
+ win = ntohs(pkt->ptrs.tcph->th_win);
+ end_seq = seq + (uint32_t) pkt->dsize;
+ ts = 0;
+#else
+ seq = pkt->ptrs.tcph->th_seq;
+ ack = pkt->ptrs.tcph->th_ack;
+ win = pkt->ptrs.tcph->th_win;
+ end_seq = seq + (uint32_t) pkt->dsize;
+ ts = 0;
+#endif
}
#define TCP_SEGMENT_DESCRIPTOR_H
#include "flow/flow.h"
+#include "protocols/tcp.h"
#include "protocols/packet.h"
class TcpSegmentDescriptor
TcpSegmentDescriptor( Flow*, Packet* );
virtual ~TcpSegmentDescriptor();
+ const Flow* get_flow() const
+ {
+ return flow;
+ }
+
+ const Packet* get_pkt() const
+ {
+ return pkt;
+ }
+ const tcp::TCPHdr* get_tcph() const
+ {
+ return tcph;
+ }
+
uint32_t get_ack() const
{
return ack;
return end_seq;
}
- const Flow* get_flow() const
+ uint32_t get_seq() const
{
- return flow;
+ return seq;
}
- const Packet* get_pkt() const
+ uint32_t get_ts() const
{
- return pkt;
+ return ts;
}
- uint32_t get_seq() const
+ uint16_t get_win() const
{
- return seq;
+ return win;
}
- uint32_t get_ts() const
+ uint16_t get_dst_port() const
+ {
+ return dst_port;
+ }
+
+ uint16_t get_src_port() const
{
- return ts;
+ return src_port;
}
- uint32_t get_win() const
+ uint8_t get_direction() const
{
- return win;
+ return direction;
+ }
+
+ void set_direction(uint8_t direction)
+ {
+ this->direction = direction;
+ }
+
+ uint32_t get_data_len() const
+ {
+ return data_len;
+ }
+
+ void set_data_len(uint32_t data_len)
+ {
+ this->data_len = data_len;
}
private:
- Packet* pkt;
Flow* flow;
+ Packet* pkt;
+
+ uint8_t direction;
+ const tcp::TCPHdr* tcph;
+ uint32_t data_len;
+ uint16_t src_port;
+ uint16_t dst_port;
uint32_t seq;
uint32_t ack;
- uint32_t win;
+ uint16_t win;
uint32_t end_seq;
uint32_t ts;
};
#include "tcp_state_handler.h"
-TcpStateHandler::TcpStateHandler()
+#include "main/snort_debug.h"
+
+#ifdef UNIT_TEST
+#include "test/catch.hpp"
+#include "stream_tcp_unit_test.h"
+#endif
+
+
+TcpStateHandler::TcpStateHandler() :
+ tcp_event( TcpStreamTracker::TCP_MAX_EVENTS )
{
// TODO Auto-generated constructor stub
// TODO Auto-generated destructor stub
}
+
void TcpStateHandler::eval( TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker )
{
- TcpStateMachine::TcpEvents tcp_event = TcpStateMachine::TCP_MAX_EVENTS;
-
- switch( tcp_event )
+ switch( tcp_event = tracker.get_tcp_event() )
{
- case TcpStateMachine::TCP_SYN_SENT_EVENT:
+ case TcpStreamTracker::TCP_SYN_SENT_EVENT:
syn_sent( tcp_seg, tracker );
break;
- case TcpStateMachine::TCP_SYN_RECV_EVENT:
+ case TcpStreamTracker::TCP_SYN_RECV_EVENT:
syn_recv( tcp_seg, tracker );
break;
- case TcpStateMachine::TCP_SYN_ACK_SENT_EVENT:
+ case TcpStreamTracker::TCP_SYN_ACK_SENT_EVENT:
syn_ack_sent( tcp_seg, tracker );
break;
- case TcpStateMachine::TCP_SYN_ACK_RECV_EVENT:
+ case TcpStreamTracker::TCP_SYN_ACK_RECV_EVENT:
syn_ack_recv( tcp_seg, tracker );
break;
- case TcpStateMachine::TCP_ACK_SENT_EVENT:
+ case TcpStreamTracker::TCP_ACK_SENT_EVENT:
ack_sent( tcp_seg, tracker );
break;
- case TcpStateMachine::TCP_ACK_RECV_EVENT:
+ case TcpStreamTracker::TCP_ACK_RECV_EVENT:
ack_recv( tcp_seg, tracker );
break;
- case TcpStateMachine::TCP_DATA_SEG_SENT_EVENT:
+ case TcpStreamTracker::TCP_DATA_SEG_SENT_EVENT:
data_seg_sent( tcp_seg, tracker );
break;
- case TcpStateMachine::TCP_DATA_SEG_RECV_EVENT:
+ case TcpStreamTracker::TCP_DATA_SEG_RECV_EVENT:
data_seg_recv( tcp_seg, tracker );
break;
- case TcpStateMachine::TCP_FIN_SENT_EVENT:
+ case TcpStreamTracker::TCP_FIN_SENT_EVENT:
fin_sent( tcp_seg, tracker );
break;
- case TcpStateMachine::TCP_FIN_RECV_EVENT:
+ case TcpStreamTracker::TCP_FIN_RECV_EVENT:
fin_recv( tcp_seg, tracker );
break;
- case TcpStateMachine::TCP_RST_SENT_EVENT:
+ case TcpStreamTracker::TCP_RST_SENT_EVENT:
rst_sent( tcp_seg, tracker );
break;
- case TcpStateMachine::TCP_RST_RECV_EVENT:
+ case TcpStreamTracker::TCP_RST_RECV_EVENT:
rst_recv( tcp_seg, tracker );
break;
- case TcpStateMachine::TCP_MAX_EVENTS:
+ case TcpStreamTracker::TCP_MAX_EVENTS:
default:
- cout << "Invalid Tcp Event " << tcp_event << endl;
+ cout << "Invalid Tcp Event " << tracker.get_tcp_event() << endl;
break;
}
void TcpStateHandler::default_state_action( TcpSegmentDescriptor* tcp_seg, TcpStreamTracker* tracker, const char* func_name )
{
- cout << "Default Implementation of " << func_name << "tcp_seg: " << tcp_seg << "tracker: " << tracker << endl;
+ DebugFormat(DEBUG_STREAM_STATE, "Default Implementation of: %s tcp_seg: %p tracker: %p\n",
+ func_name, tcp_seg, tracker );
+
+ tcp_event = tracker->get_tcp_event();
}
void TcpStateHandler::syn_sent( TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker )
default_state_action( &tcp_seg, &tracker, __func__ );
}
+#ifdef UNIT_TEST
+
+SCENARIO("TCP State Handler Base Class", "[state_handlers][stream_tcp]")
+{
+ // initialization code here
+ Flow* flow = new Flow;
+ TcpStateHandler* tsh = new TcpStateHandler;
+ TcpStreamTracker* client_tracker = new TcpStreamTracker( true );
+ TcpStreamTracker* server_tracker = new TcpStreamTracker( false );
+
+ GIVEN("a SYN Packet")
+ {
+ Packet* pkt = get_syn_packet( flow );
+ REQUIRE( ( pkt != nullptr ) );
+
+ WHEN("SYN is sent")
+ {
+ TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt );
+ REQUIRE( ( tcp_seg != nullptr ) );
+ client_tracker->set_tcp_event( TcpStreamTracker::TCP_SYN_SENT_EVENT );
+ tsh->eval( *tcp_seg, *client_tracker );
+ THEN("Event should be TCP_SYN_SENT_EVENT")
+ {
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ }
+ delete tcp_seg;
+ }
+
+ SECTION("SYN is received")
+ {
+ TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt );
+ REQUIRE( ( tcp_seg != nullptr ) );
+ server_tracker->set_tcp_event( TcpStreamTracker::TCP_SYN_RECV_EVENT );
+ tsh->eval( *tcp_seg, *server_tracker );
+ CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) );
+ delete tcp_seg;
+ }
+
+ delete pkt;
+ }
+
+ SECTION("syn_ack_packet")
+ {
+ Packet* pkt = get_syn_ack_packet( flow );
+ REQUIRE( ( pkt != nullptr ) );
+
+ SECTION("syn_ack_sent")
+ {
+ TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt );
+ REQUIRE( ( tcp_seg != nullptr ) );
+ client_tracker->set_tcp_event( TcpStreamTracker::TCP_SYN_ACK_SENT_EVENT );
+ tsh->eval( *tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ delete tcp_seg;
+ }
+
+ SECTION("syn_ack_recv")
+ {
+ TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt );
+ REQUIRE( ( tcp_seg != nullptr ) );
+ server_tracker->set_tcp_event( TcpStreamTracker::TCP_SYN_ACK_RECV_EVENT );
+ tsh->eval( *tcp_seg, *server_tracker );
+ CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) );
+ delete tcp_seg;
+ }
+
+ delete pkt;
+ }
+
+ SECTION("ack_packet")
+ {
+ Packet* pkt = get_ack_packet( flow );
+ REQUIRE( ( pkt != nullptr ) );
+
+ SECTION("ack_sent")
+ {
+ TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt );
+ REQUIRE( ( tcp_seg != nullptr ) );
+ client_tracker->set_tcp_event( TcpStreamTracker::TCP_ACK_SENT_EVENT );
+ tsh->eval( *tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ delete tcp_seg;
+ }
+
+ SECTION("ack_recv")
+ {
+ TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt );
+ REQUIRE( ( tcp_seg != nullptr ) );
+ server_tracker->set_tcp_event( TcpStreamTracker::TCP_ACK_RECV_EVENT );
+ tsh->eval( *tcp_seg, *server_tracker );
+ CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) );
+ delete tcp_seg;
+ }
+
+ delete pkt;
+ }
+
+ SECTION("data_seg_packet")
+ {
+ Packet* pkt = get_data_packet( flow );
+ REQUIRE( ( pkt != nullptr ) );
+
+ SECTION("data_seg_sent")
+ {
+ TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt );
+ REQUIRE( ( tcp_seg != nullptr ) );
+ client_tracker->set_tcp_event( TcpStreamTracker::TCP_DATA_SEG_SENT_EVENT );
+ tsh->eval( *tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ delete tcp_seg;
+ }
+
+ SECTION("data_seg_recv")
+ {
+ TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt );
+ REQUIRE( ( tcp_seg != nullptr ) );
+ server_tracker->set_tcp_event( TcpStreamTracker::TCP_DATA_SEG_RECV_EVENT );
+ tsh->eval( *tcp_seg, *server_tracker );
+ CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) );
+ delete tcp_seg;
+ }
+
+ delete pkt;
+ }
+
+ SECTION("fin_packet")
+ {
+ Packet* pkt = get_fin_packet( flow );
+ REQUIRE( ( pkt != nullptr ) );
+
+ SECTION("fin_sent")
+ {
+ TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt );
+ REQUIRE( ( tcp_seg != nullptr ) );
+ client_tracker->set_tcp_event( TcpStreamTracker::TCP_FIN_SENT_EVENT );
+ tsh->eval( *tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ delete tcp_seg;
+ }
+
+ SECTION("fin_recv")
+ {
+ TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt );
+ REQUIRE( ( tcp_seg != nullptr ) );
+ server_tracker->set_tcp_event( TcpStreamTracker::TCP_FIN_RECV_EVENT );
+ tsh->eval( *tcp_seg, *server_tracker );
+ CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) );
+ delete tcp_seg;
+ }
+
+ delete pkt;
+ }
+
+ SECTION("rst_packet")
+ {
+ Packet* pkt = get_rst_packet( flow );
+ REQUIRE( ( pkt != nullptr ) );
+
+ SECTION("rst_sent")
+ {
+ TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt );
+ REQUIRE( ( tcp_seg != nullptr ) );
+ client_tracker->set_tcp_event( TcpStreamTracker::TCP_RST_SENT_EVENT );
+ tsh->eval( *tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ delete tcp_seg;
+ }
+
+ SECTION("rst_recv")
+ {
+ TcpSegmentDescriptor* tcp_seg = new TcpSegmentDescriptor( flow, pkt );
+ REQUIRE( ( tcp_seg != nullptr ) );
+ server_tracker->set_tcp_event( TcpStreamTracker::TCP_RST_RECV_EVENT );
+ tsh->eval( *tcp_seg, *server_tracker );
+ CHECK( ( tsh->get_tcp_event() == server_tracker->get_tcp_event() ) );
+ delete tcp_seg;
+ }
+
+ delete pkt;
+ }
+
+ delete flow;
+ delete tsh;
+ delete client_tracker;
+ delete server_tracker;
+
+}
+
+#endif
virtual void eval(TcpSegmentDescriptor&, TcpStreamTracker&);
+ TcpStreamTracker::TcpEvents get_tcp_event() const {
+ return tcp_event;
+ }
+
protected:
virtual void syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&);
virtual void syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&);
void default_state_action( TcpSegmentDescriptor*, TcpStreamTracker*, const char* );
+ TcpStreamTracker::TcpEvents tcp_event;
};
#endif
}
+void TcpStateMachine::eval( TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker )
+{
+ tracker.set_tcp_event( tcp_seg, tracker.is_client_tracker( ) );
+ tcp_state_handlers[ tracker.get_tcp_state( ) ]->eval( tcp_seg, tracker );
+}
#ifndef TCP_STATE_MACHINE_H
#define TCP_STATE_MACHINE_H
+#include "tcp_state_handler.h"
+#include "tcp_stream_tracker.h"
+#include "tcp_segment_descriptor.h"
+
extern const char* tcp_state_names[];
extern const char* tcp_event_names[];
class TcpStateMachine
{
public:
- enum TcpStates
- {
- TCP_LISTEN,
- TCP_SYN_SENT,
- TCP_SYN_RECV,
- TCP_ESTABLISHED,
- TCP_FIN_WAIT1,
- TCP_FIN_WAIT2,
- TCP_CLOSE_WAIT,
- TCP_CLOSING,
- TCP_LAST_ACK,
- TCP_TIME_WAIT,
- TCP_CLOSED,
- TCP_MAX_STATES
- };
-
- enum TcpEvents
- {
- TCP_SYN_SENT_EVENT,
- TCP_SYN_RECV_EVENT,
- TCP_SYN_ACK_SENT_EVENT,
- TCP_SYN_ACK_RECV_EVENT,
- TCP_ACK_SENT_EVENT,
- TCP_ACK_RECV_EVENT,
- TCP_DATA_SEG_SENT_EVENT,
- TCP_DATA_SEG_RECV_EVENT,
- TCP_FIN_SENT_EVENT,
- TCP_FIN_RECV_EVENT,
- TCP_RST_SENT_EVENT,
- TCP_RST_RECV_EVENT,
- TCP_MAX_EVENTS
- };
-
virtual ~TcpStateMachine();
+ virtual void eval(TcpSegmentDescriptor&, TcpStreamTracker&);
+
private:
TcpStateMachine();
+
+ TcpStateHandler *tcp_state_handlers[ TcpStreamTracker::TCP_MAX_STATES ];
};
#endif
// Created on: Jun 24, 2015
#include "tcp_stream_tracker.h"
+#include "stream/stream.h"
-TcpStreamTracker::TcpStreamTracker( bool client )
+TcpStreamTracker::TcpStreamTracker( bool client ) :
+ client_tracker( client )
{
- tcp_state = ( client ) ? TcpStateMachine::TCP_CLOSED : TcpStateMachine::TCP_LISTEN;
+ tcp_state = ( client ) ? TCP_CLOSED : TCP_LISTEN;
+ tcp_event = TCP_MAX_EVENTS;
}
TcpStreamTracker::~TcpStreamTracker()
// TODO Auto-generated destructor stub
}
+void TcpStreamTracker::set_tcp_event( TcpSegmentDescriptor &tcp_seg, bool client )
+{
+ bool talker;
+
+ if( tcp_seg.get_direction( ) == FROM_CLIENT )
+ talker = ( client ) ? true : false;
+ else
+ talker = ( client ) ? false : true;
+
+ if( talker )
+ {
+ if( tcp_seg.get_tcph()->is_syn_only() )
+ tcp_event = TCP_SYN_SENT_EVENT;
+ else if( tcp_seg.get_tcph()->is_syn_ack() )
+ tcp_event = TCP_SYN_ACK_SENT_EVENT;
+ else if( tcp_seg.get_tcph()->is_ack() )
+ {
+ if( tcp_seg.get_data_len() > 0 )
+ tcp_event = TCP_DATA_SEG_SENT_EVENT;
+ else
+ tcp_event = TCP_ACK_SENT_EVENT;
+ }
+ else if( tcp_seg.get_tcph()->is_rst() )
+ tcp_event = TCP_RST_SENT_EVENT;
+ else if( tcp_seg.get_tcph()->is_fin( ) )
+ tcp_event = TCP_FIN_SENT_EVENT;
+ else
+ tcp_event = TCP_MAX_EVENTS;
+ }
+ else // server is listening events
+ {
+ if( tcp_seg.get_tcph()->is_syn_only() )
+ tcp_event = TCP_SYN_RECV_EVENT;
+ else if( tcp_seg.get_tcph()->is_syn_ack() )
+ tcp_event = TCP_SYN_ACK_RECV_EVENT;
+ else if( tcp_seg.get_tcph()->is_ack() )
+ {
+ if( tcp_seg.get_data_len() > 0 )
+ tcp_event = TCP_DATA_SEG_RECV_EVENT;
+ else
+ tcp_event = TCP_ACK_RECV_EVENT;
+ }
+ else if( tcp_seg.get_tcph()->is_rst() )
+ tcp_event = TCP_RST_RECV_EVENT;
+ else if( tcp_seg.get_tcph()->is_fin( ) )
+ tcp_event = TCP_FIN_RECV_EVENT;
+ }
+}
#ifndef TCP_STREAM_TRACKER_H
#define TCP_STREAM_TRACKER_H
-#include "tcp_state_machine.h"
+#include "stdint.h"
+
+#include "tcp_segment_descriptor.h"
class TcpStreamTracker
{
public:
+ enum TcpStates
+ {
+ TCP_LISTEN,
+ TCP_SYN_SENT,
+ TCP_SYN_RECV,
+ TCP_ESTABLISHED,
+ TCP_FIN_WAIT1,
+ TCP_FIN_WAIT2,
+ TCP_CLOSE_WAIT,
+ TCP_CLOSING,
+ TCP_LAST_ACK,
+ TCP_TIME_WAIT,
+ TCP_CLOSED,
+ TCP_MAX_STATES
+ };
+
+ enum TcpEvents
+ {
+ TCP_SYN_SENT_EVENT,
+ TCP_SYN_RECV_EVENT,
+ TCP_SYN_ACK_SENT_EVENT,
+ TCP_SYN_ACK_RECV_EVENT,
+ TCP_ACK_SENT_EVENT,
+ TCP_ACK_RECV_EVENT,
+ TCP_DATA_SEG_SENT_EVENT,
+ TCP_DATA_SEG_RECV_EVENT,
+ TCP_FIN_SENT_EVENT,
+ TCP_FIN_RECV_EVENT,
+ TCP_RST_SENT_EVENT,
+ TCP_RST_RECV_EVENT,
+ TCP_MAX_EVENTS
+ };
+
TcpStreamTracker( bool );
virtual ~TcpStreamTracker();
-private:
- TcpStateMachine::TcpStates tcp_state;
+ bool is_client_tracker() const {
+ return client_tracker;
+ }
+
+ TcpStates get_tcp_state() const {
+ return tcp_state;
+ }
+
+ void set_tcp_state(TcpStates tcp_state) {
+ this->tcp_state = tcp_state;
+ }
+
+ TcpEvents get_tcp_event() const {
+ return tcp_event;
+ }
+
+ void set_tcp_event( TcpSegmentDescriptor &tcp_seg, bool client );
+
+ void set_tcp_event(TcpEvents tcp_event) {
+ this->tcp_event = tcp_event;
+ }
+
+ uint32_t get_irs() const {
+ return irs;
+ }
+
+ void set_irs(uint32_t irs) {
+ this->irs = irs;
+ }
+
+ uint32_t get_iss() const {
+ return iss;
+ }
+
+ void set_iss(uint32_t iss) {
+ this->iss = iss;
+ }
+
+ uint32_t get_rcv_nxt() const {
+ return rcv_nxt;
+ }
+
+ void set_rcv_nxt(uint32_t rcv_nxt) {
+ this->rcv_nxt = rcv_nxt;
+ }
+
+ uint16_t get_rcv_up() const {
+ return rcv_up;
+ }
+
+ void set_rcv_up(uint16_t rcv_up) {
+ this->rcv_up = rcv_up;
+ }
+
+ uint16_t get_rcv_wnd() const {
+ return rcv_wnd;
+ }
+
+ void set_rcv_wnd(uint16_t rcv_wnd) {
+ this->rcv_wnd = rcv_wnd;
+ }
+
+ uint32_t get_snd_nxt() const {
+ return snd_nxt;
+ }
+
+ void set_snd_nxt(uint32_t snd_nxt) {
+ this->snd_nxt = snd_nxt;
+ }
+
+ uint32_t get_snd_una() const {
+ return snd_una;
+ }
+
+ void set_snd_una(uint32_t snd_una) {
+ this->snd_una = snd_una;
+ }
+
+ uint16_t get_snd_up() const {
+ return snd_up;
+ }
+
+ void set_snd_up(uint16_t snd_up) {
+ this->snd_up = snd_up;
+ }
+
+ uint32_t get_snd_wl1() const {
+ return snd_wl1;
+ }
+
+ void set_snd_wl1(uint32_t snd_wl1) {
+ this->snd_wl1 = snd_wl1;
+ }
+
+ uint32_t get_snd_wl2() const {
+ return snd_wl2;
+ }
+
+ void set_snd_wl2(uint32_t snd_wl2) {
+ this->snd_wl2 = snd_wl2;
+ }
+
+ uint16_t get_snd_wnd() const {
+ return snd_wnd;
+ }
+
+ void set_snd_wnd(uint16_t snd_wnd) {
+ this->snd_wnd = snd_wnd;
+ }
+
+ uint32_t get_ts_last_packet() const {
+ return ts_last_packet;
+ }
+
+ void set_ts_last_packet(uint32_t ts_last_packet) {
+ this->ts_last_packet = ts_last_packet;
+ }
+
+protected:
+ uint32_t snd_una; // SND.UNA - send unacknowledged
+ uint32_t snd_nxt; // SND.NXT - send next
+ uint16_t snd_wnd; // SND.WND - send window
+ uint16_t snd_up; // SND.UP - send urgent pointer
+ uint32_t snd_wl1; // SND.WL1 - segment sequence number used for last window update
+ uint32_t snd_wl2; // SND.WL2 - segment acknowledgment number used for last window update
+ uint32_t iss; // ISS - initial send sequence number
+
+ uint32_t rcv_nxt; // RCV.NXT - receive next
+ uint16_t rcv_wnd; // RCV.WND - receive window
+ uint16_t rcv_up; // RCV.UP - receive urgent pointer
+ uint32_t irs; // IRS - initial receive sequence number
+
+ uint32_t ts_last_packet; // timestamp of last packet we got
+
+ bool client_tracker;
+ TcpStates tcp_state;
+ TcpEvents tcp_event;
};
#endif
tcp_reassembly.cc
tcp_session.cc
tcp_session.h
+ tcp_closed_state.cc
tcp_listen_state.cc
tcp_syn_sent_state.cc
tcp_syn_recv_state.cc
tcp_reassembly.cc \
tcp_session.cc \
tcp_session.h \
+tcp_closed_state.h \
+tcp_closed_state.cc \
tcp_listen_state.cc \
tcp_listen_state.h \
tcp_syn_sent_state.cc \
#include "hash/sfhashfcn.h"
#include "time/profiler.h"
+#ifdef UNIT_TEST
+#include "test/catch.hpp"
+#include "stream/libtcp/stream_tcp_unit_test.h"
+#endif
+
//-------------------------------------------------------------------------
// stream_reassemble
//-------------------------------------------------------------------------
const BaseApi* ips_stream_reassemble = &reassemble_api.base;
+#ifdef UNIT_TEST
+
+#include "framework/cursor.h"
+
+TEST_CASE("IPS Stream Reassemble", "[ips_stream_reassemble][stream_tcp]")
+{
+ // initialization code here
+ REQUIRE( ( ips_stream_reassemble->api_version == ((BASE_API_VERSION << 16) | 0) ) );
+ REQUIRE( ( strcmp( ips_stream_reassemble->name, s_name ) == 0 ) );
+ ReassembleModule* reassembler = ( ReassembleModule* ) ips_stream_reassemble->mod_ctor();
+ REQUIRE( ( reassembler != nullptr ) );
+
+ Flow* flow = new Flow;
+ Packet* pkt = get_syn_packet( flow );
+ pkt->flow->session = new TcpSession( flow );
+ Cursor cursor( pkt );
+
+ SECTION("reassembler initialization")
+ {
+ bool status = reassembler->begin( nullptr, 0, snort_conf );
+ CHECK( status );
+ CHECK( ( reassembler->srod.enable == 0 ) );
+ CHECK( ( reassembler->srod.direction == 0 ) );
+ CHECK( ( reassembler->srod.alert == 1 ) );
+ CHECK( ( reassembler->srod.fastpath == 0 ) );
+ }
+
+ SECTION("eval enable off")
+ {
+ reassembler->srod.direction = SSN_DIR_FROM_SERVER;
+ IpsOption* ropt = reassemble_api.ctor( reassembler, nullptr );
+ int rc = ropt->eval( cursor, pkt );
+ CHECK( ( rc == DETECTION_OPTION_MATCH ) );
+ StreamSplitter* ss = stream.get_splitter( flow, true );
+ CHECK( ( ss != nullptr ) );
+ CHECK( ( !ss->is_paf() ) );
+ CHECK( ( ( ( TcpSession* ) pkt->flow->session)->server.flush_policy
+ == STREAM_FLPOLICY_IGNORE ) );
+ }
+}
+
+
+#endif
/* the seq num wrapping case... */
client_size = tcpssn->client.isn - tcpssn->client.l_nxt_seq;
}
+
if (tcpssn->server.l_nxt_seq > tcpssn->server.isn)
{
/* the normal case... */
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// tcp_closed_state.cc author davis mcpherson <davmcphe@@cisco.com>
+// Created on: Jul 30, 2015
+
+#include "tcp_closed_state.h"
+
+#include "stream/stream.h"
+
+#ifdef UNIT_TEST
+#include "test/catch.hpp"
+#include "stream/libtcp/stream_tcp_unit_test.h"
+#endif
+
+TcpClosedState::TcpClosedState()
+{
+ // TODO Auto-generated constructor stub
+
+}
+
+TcpClosedState::~TcpClosedState()
+{
+ // TODO Auto-generated destructor stub
+}
+
+void TcpClosedState::syn_sent( TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker )
+{
+ tracker.set_iss( tcp_seg.get_seq() );
+ tracker.set_snd_una( tcp_seg.get_seq() + 1 );
+ tracker.set_snd_nxt( tcp_seg.get_end_seq() );
+ tracker.set_snd_wnd( tcp_seg.get_win() );
+ tracker.set_ts_last_packet( tcp_seg.get_pkt()->pkth->ts.tv_sec );
+
+ tracker.set_tcp_state( TcpStreamTracker::TCP_SYN_SENT );
+}
+
+void TcpClosedState::syn_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker)
+{
+ default_state_action( &tcp_seg, &tracker, __func__ );
+}
+
+void TcpClosedState::syn_ack_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker)
+{
+ default_state_action( &tcp_seg, &tracker, __func__ );
+}
+
+void TcpClosedState::syn_ack_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker)
+{
+ default_state_action( &tcp_seg, &tracker, __func__ );
+}
+
+void TcpClosedState::ack_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker)
+{
+ default_state_action( &tcp_seg, &tracker, __func__ );
+}
+
+void TcpClosedState::ack_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker)
+{
+ default_state_action( &tcp_seg, &tracker, __func__ );
+}
+
+void TcpClosedState::data_seg_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker)
+{
+ default_state_action( &tcp_seg, &tracker, __func__ );
+}
+
+void TcpClosedState::data_seg_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker)
+{
+ default_state_action( &tcp_seg, &tracker, __func__ );
+}
+
+void TcpClosedState::fin_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker)
+{
+ default_state_action( &tcp_seg, &tracker, __func__ );
+}
+
+void TcpClosedState::fin_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker)
+{
+ default_state_action( &tcp_seg, &tracker, __func__ );
+}
+
+void TcpClosedState::rst_sent(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker)
+{
+ default_state_action( &tcp_seg, &tracker, __func__ );
+}
+
+void TcpClosedState::rst_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tracker)
+{
+ default_state_action( &tcp_seg, &tracker, __func__ );
+}
+
+#ifdef UNIT_TEST
+
+TEST_CASE("TCP State Closed", "[tcp_closed_state][stream_tcp]")
+{
+ // initialization code here
+ Flow* flow = new Flow;
+ TcpStateHandler* tsh = new TcpClosedState;
+ TcpStreamTracker* client_tracker = new TcpStreamTracker( true );
+
+ SECTION("syn_packet")
+ {
+ Packet* pkt = get_syn_packet( flow );
+ REQUIRE( ( pkt != nullptr ) );
+
+ SECTION("syn_sent")
+ {
+ flow->ssn_state.direction = FROM_CLIENT;
+ TcpSegmentDescriptor tcp_seg( flow, pkt );
+ client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) );
+ tsh->eval( tcp_seg, *client_tracker );
+ CHECK( TcpStreamTracker::TCP_SYN_SENT_EVENT == client_tracker->get_tcp_event() );
+ CHECK( ( client_tracker->get_iss() == 9050 ) );
+ CHECK( ( client_tracker->get_snd_una() == 9051 ) );
+ CHECK( ( client_tracker->get_snd_nxt() == 9050 ) );
+ CHECK( ( client_tracker->get_snd_wnd() == 8192 ) );
+ }
+
+ SECTION("syn_recv")
+ {
+ flow->ssn_state.direction = FROM_SERVER;
+ TcpSegmentDescriptor tcp_seg( flow, pkt );
+ client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) );
+ tsh->eval( tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ }
+
+ delete pkt;
+ }
+
+ SECTION("syn_ack_packet")
+ {
+ Packet* pkt = get_syn_ack_packet( flow );
+ REQUIRE( ( pkt != nullptr ) );
+
+ SECTION("syn_ack_sent")
+ {
+ flow->ssn_state.direction = FROM_CLIENT;
+ TcpSegmentDescriptor tcp_seg( flow, pkt );
+ client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) );
+ tsh->eval( tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ }
+
+ SECTION("syn_ack_recv")
+ {
+ flow->ssn_state.direction = FROM_SERVER;
+ TcpSegmentDescriptor tcp_seg( flow, pkt );
+ client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) );
+ tsh->eval( tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ }
+
+ delete pkt;
+ }
+
+ SECTION("ack_packet")
+ {
+ Packet* pkt = get_ack_packet( flow );
+ REQUIRE( ( pkt != nullptr ) );
+
+ SECTION("ack_sent")
+ {
+ flow->ssn_state.direction = FROM_CLIENT;
+ TcpSegmentDescriptor tcp_seg( flow, pkt );
+ client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) );
+ tsh->eval( tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ }
+
+ SECTION("ack_recv")
+ {
+ flow->ssn_state.direction = FROM_SERVER;
+ TcpSegmentDescriptor tcp_seg( flow, pkt );
+ client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) );
+ tsh->eval( tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ }
+
+ delete pkt;
+ }
+
+ SECTION("data_seg_packet")
+ {
+ Packet* pkt = get_data_packet( flow );
+ REQUIRE( ( pkt != nullptr ) );
+
+ SECTION("data_seg_sent")
+ {
+ flow->ssn_state.direction = FROM_CLIENT;
+ TcpSegmentDescriptor tcp_seg( flow, pkt );
+ client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) );
+ tsh->eval( tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ }
+
+ SECTION("data_seg_recv")
+ {
+ flow->ssn_state.direction = FROM_SERVER;
+ TcpSegmentDescriptor tcp_seg( flow, pkt );
+ client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) );
+ tsh->eval( tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ }
+
+ delete pkt;
+ }
+
+ SECTION("fin_packet")
+ {
+ Packet* pkt = get_fin_packet( flow );
+ REQUIRE( ( pkt != nullptr ) );
+
+ SECTION("fin_sent")
+ {
+ flow->ssn_state.direction = FROM_CLIENT;
+ TcpSegmentDescriptor tcp_seg( flow, pkt );
+ client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) );
+ tsh->eval( tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ }
+
+ SECTION("fin_recv")
+ {
+ flow->ssn_state.direction = FROM_SERVER;
+ TcpSegmentDescriptor tcp_seg( flow, pkt );
+ client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) );
+ tsh->eval( tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ }
+
+ delete pkt;
+ }
+
+ SECTION("rst_packet")
+ {
+ Packet* pkt = get_rst_packet( flow );
+ REQUIRE( ( pkt != nullptr ));
+
+ SECTION("rst_sent")
+ {
+ flow->ssn_state.direction = FROM_CLIENT;
+ TcpSegmentDescriptor tcp_seg( flow, pkt );
+ client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) );
+ tsh->eval( tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ));
+ }
+
+ SECTION("rst_recv")
+ {
+ flow->ssn_state.direction = FROM_SERVER;
+ TcpSegmentDescriptor tcp_seg( flow, pkt );
+ client_tracker->set_tcp_event( tcp_seg, client_tracker->is_client_tracker( ) );
+ tsh->eval( tcp_seg, *client_tracker );
+ CHECK( ( tsh->get_tcp_event() == client_tracker->get_tcp_event() ) );
+ }
+
+ delete pkt;
+ }
+
+ delete flow;
+ delete tsh;
+ delete client_tracker;
+}
+
+#endif
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// tcp_closed_state.h author davis mcpherson <davmcphe@cisco.com>
+// Created on: Jul 30, 2015
+
+#ifndef TCP_CLOSED_STATE_H
+#define TCP_CLOSED_STATE_H
+
+#include "stream/libtcp/tcp_state_handler.h"
+
+class TcpClosedState: public TcpStateHandler
+{
+public:
+ TcpClosedState();
+ virtual ~TcpClosedState();
+
+ void syn_sent(TcpSegmentDescriptor&, TcpStreamTracker&);
+ void syn_recv(TcpSegmentDescriptor&, TcpStreamTracker&);
+ void syn_ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&);
+ void syn_ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&);
+ void ack_sent(TcpSegmentDescriptor&, TcpStreamTracker&);
+ void ack_recv(TcpSegmentDescriptor&, TcpStreamTracker&);
+ void data_seg_sent(TcpSegmentDescriptor&, TcpStreamTracker&);
+ void data_seg_recv(TcpSegmentDescriptor&, TcpStreamTracker&);
+ void fin_sent(TcpSegmentDescriptor&, TcpStreamTracker&);
+ void fin_recv(TcpSegmentDescriptor&, TcpStreamTracker&);
+ void rst_sent(TcpSegmentDescriptor&, TcpStreamTracker&);
+ void rst_recv(TcpSegmentDescriptor&, TcpStreamTracker&);
+};
+
+#endif
#include "tcp_normalization.h"
#include "tcp_reassembly.h"
#include "tcp_debug_trace.h"
+
+#include "stream/libtcp/tcp_state_handler.h"
+#include "tcp_closed_state.h"
+#include "tcp_listen_state.h"
+#include "tcp_syn_sent_state.h"
+#include "tcp_syn_recv_state.h"
// TBD-EDM
#include "main/snort_types.h"
bool TcpSession::setup(Packet*)
{
+
+ TcpStateHandler* tsh = new TcpStateHandler;
+
// FIXIT-L this it should not be necessary to reset here
reset();
daq_flags = address_space_id = 0;
#endif
+ delete tsh;
+ tsh = new TcpClosedState;
+ delete tsh;
+ tsh = new TcpListenState;
+ delete tsh;
+ tsh = new TcpSynSentState;
+ delete tsh;
+
tcpStats.sessions++;
return true;
}
#include "tcp_syn_sent_state.h"
+#ifdef UNIT_TEST
+#include "test/catch.hpp"
+#endif
+
TcpSynSentState::TcpSynSentState()
{
// TODO Auto-generated constructor stub
default_state_action( &tcp_seg, &tracker, __func__ );
}
+#ifdef UNIT_TEST
+
+#endif