From: davis mcpherson Date: Mon, 31 Aug 2015 15:01:55 +0000 (+0000) Subject: catch unit test updates, making libtcp real X-Git-Tag: 3.0.0-233~846^2~4^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=42e2bc63e7bf35c04397bc2d2036efecfc8ada4f;p=thirdparty%2Fsnort3.git catch unit test updates, making libtcp real --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index df1b7a184..64415a757 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -98,8 +98,8 @@ target_link_libraries( snort stream_base stream_ip stream_icmp - stream_libtcp stream_tcp + stream_libtcp stream_udp stream_user stream_file diff --git a/src/Makefile.am b/src/Makefile.am index 5396e6fcc..2076e0e66 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,8 +60,8 @@ stream/libstream.a \ 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 \ diff --git a/src/protocols/tcp.h b/src/protocols/tcp.h index ef38ae7fc..1fff8337f 100644 --- a/src/protocols/tcp.h +++ b/src/protocols/tcp.h @@ -130,6 +130,9 @@ struct TCPHdr 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; } diff --git a/src/stream/libtcp/CMakeLists.txt b/src/stream/libtcp/CMakeLists.txt index 767ddcc83..c992491cd 100644 --- a/src/stream/libtcp/CMakeLists.txt +++ b/src/stream/libtcp/CMakeLists.txt @@ -1,6 +1,8 @@ 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 ) diff --git a/src/stream/libtcp/Makefile.am b/src/stream/libtcp/Makefile.am index a00832b45..aadeb44fa 100644 --- a/src/stream/libtcp/Makefile.am +++ b/src/stream/libtcp/Makefile.am @@ -9,4 +9,7 @@ tcp_stream_tracker.h \ 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 diff --git a/src/stream/libtcp/dev_notes.txt b/src/stream/libtcp/dev_notes.txt new file mode 100644 index 000000000..12a79d004 --- /dev/null +++ b/src/stream/libtcp/dev_notes.txt @@ -0,0 +1,18 @@ +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. + diff --git a/src/stream/libtcp/stream_tcp_unit_test.cc b/src/stream/libtcp/stream_tcp_unit_test.cc new file mode 100644 index 000000000..39faf9999 --- /dev/null +++ b/src/stream/libtcp/stream_tcp_unit_test.cc @@ -0,0 +1,134 @@ +//-------------------------------------------------------------------------- +// 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 +// Created on: Jul 30, 2015 + +#ifndef STREAM_LIBTCP_UNIT_TEST +#define STREAM_LIBTCP_UNIT_TEST + +#include + +#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 + diff --git a/src/stream/libtcp/stream_tcp_unit_test.h b/src/stream/libtcp/stream_tcp_unit_test.h new file mode 100644 index 000000000..98d598812 --- /dev/null +++ b/src/stream/libtcp/stream_tcp_unit_test.h @@ -0,0 +1,37 @@ +//-------------------------------------------------------------------------- +// 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 +// Created on: Jul 30, 2015 + +#ifndef STREAM_LIBTCP_UNIT_TEST +#define STREAM_LIBTCP_UNIT_TEST + +#include + +#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 + diff --git a/src/stream/libtcp/tcp_segment_descriptor.cc b/src/stream/libtcp/tcp_segment_descriptor.cc index acead1077..9e58153e2 100644 --- a/src/stream/libtcp/tcp_segment_descriptor.cc +++ b/src/stream/libtcp/tcp_segment_descriptor.cc @@ -21,9 +21,29 @@ #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 } diff --git a/src/stream/libtcp/tcp_segment_descriptor.h b/src/stream/libtcp/tcp_segment_descriptor.h index fa8ce6ee3..365726fcb 100644 --- a/src/stream/libtcp/tcp_segment_descriptor.h +++ b/src/stream/libtcp/tcp_segment_descriptor.h @@ -23,6 +23,7 @@ #define TCP_SEGMENT_DESCRIPTOR_H #include "flow/flow.h" +#include "protocols/tcp.h" #include "protocols/packet.h" class TcpSegmentDescriptor @@ -31,6 +32,20 @@ public: 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; @@ -41,38 +56,64 @@ public: 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; }; diff --git a/src/stream/libtcp/tcp_state_handler.cc b/src/stream/libtcp/tcp_state_handler.cc index 29e162705..67efdd8d7 100644 --- a/src/stream/libtcp/tcp_state_handler.cc +++ b/src/stream/libtcp/tcp_state_handler.cc @@ -24,7 +24,16 @@ using namespace std; #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 @@ -35,63 +44,62 @@ TcpStateHandler::~TcpStateHandler() // 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; } @@ -99,7 +107,10 @@ void TcpStateHandler::eval( TcpSegmentDescriptor &tcp_seg, TcpStreamTracker &tra 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 ) @@ -162,3 +173,192 @@ void TcpStateHandler::rst_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker & 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 diff --git a/src/stream/libtcp/tcp_state_handler.h b/src/stream/libtcp/tcp_state_handler.h index afbb9b833..efba31eb3 100644 --- a/src/stream/libtcp/tcp_state_handler.h +++ b/src/stream/libtcp/tcp_state_handler.h @@ -35,6 +35,10 @@ public: 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&); @@ -51,6 +55,7 @@ protected: void default_state_action( TcpSegmentDescriptor*, TcpStreamTracker*, const char* ); + TcpStreamTracker::TcpEvents tcp_event; }; #endif diff --git a/src/stream/libtcp/tcp_state_machine.cc b/src/stream/libtcp/tcp_state_machine.cc index 349ebd12e..d31ece3a6 100644 --- a/src/stream/libtcp/tcp_state_machine.cc +++ b/src/stream/libtcp/tcp_state_machine.cc @@ -43,3 +43,8 @@ TcpStateMachine::TcpStateMachine() } +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 ); +} diff --git a/src/stream/libtcp/tcp_state_machine.h b/src/stream/libtcp/tcp_state_machine.h index 604ab460c..644f4c44a 100644 --- a/src/stream/libtcp/tcp_state_machine.h +++ b/src/stream/libtcp/tcp_state_machine.h @@ -22,49 +22,24 @@ #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 diff --git a/src/stream/libtcp/tcp_stream_tracker.cc b/src/stream/libtcp/tcp_stream_tracker.cc index cbfc62dab..57980676f 100644 --- a/src/stream/libtcp/tcp_stream_tracker.cc +++ b/src/stream/libtcp/tcp_stream_tracker.cc @@ -20,10 +20,13 @@ // 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() @@ -31,3 +34,51 @@ 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; + } +} diff --git a/src/stream/libtcp/tcp_stream_tracker.h b/src/stream/libtcp/tcp_stream_tracker.h index a37361bb9..2f681eccc 100644 --- a/src/stream/libtcp/tcp_stream_tracker.h +++ b/src/stream/libtcp/tcp_stream_tracker.h @@ -22,17 +22,187 @@ #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 diff --git a/src/stream/tcp/CMakeLists.txt b/src/stream/tcp/CMakeLists.txt index 358082d38..fd91a6aae 100644 --- a/src/stream/tcp/CMakeLists.txt +++ b/src/stream/tcp/CMakeLists.txt @@ -12,6 +12,7 @@ add_library( stream_tcp STATIC 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 diff --git a/src/stream/tcp/Makefile.am b/src/stream/tcp/Makefile.am index ede40d427..18f2121ad 100644 --- a/src/stream/tcp/Makefile.am +++ b/src/stream/tcp/Makefile.am @@ -15,6 +15,8 @@ tcp_reassembly.h \ 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 \ diff --git a/src/stream/tcp/ips_stream_reassemble.cc b/src/stream/tcp/ips_stream_reassemble.cc index 9887f05b7..0eefd5d5b 100644 --- a/src/stream/tcp/ips_stream_reassemble.cc +++ b/src/stream/tcp/ips_stream_reassemble.cc @@ -31,6 +31,11 @@ #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 //------------------------------------------------------------------------- @@ -277,3 +282,46 @@ static const IpsApi reassemble_api = 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 diff --git a/src/stream/tcp/ips_stream_size.cc b/src/stream/tcp/ips_stream_size.cc index 95a3e0c5a..606774406 100644 --- a/src/stream/tcp/ips_stream_size.cc +++ b/src/stream/tcp/ips_stream_size.cc @@ -118,6 +118,7 @@ int SizeOption::eval(Cursor&, Packet* pkt) /* 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... */ diff --git a/src/stream/tcp/tcp_closed_state.cc b/src/stream/tcp/tcp_closed_state.cc new file mode 100644 index 000000000..465dda2dd --- /dev/null +++ b/src/stream/tcp/tcp_closed_state.cc @@ -0,0 +1,282 @@ +//-------------------------------------------------------------------------- +// 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 +// 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 diff --git a/src/stream/tcp/tcp_closed_state.h b/src/stream/tcp/tcp_closed_state.h new file mode 100644 index 000000000..b545738ed --- /dev/null +++ b/src/stream/tcp/tcp_closed_state.h @@ -0,0 +1,47 @@ +//-------------------------------------------------------------------------- +// 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 +// 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 diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index d9c3c29d2..5a564624f 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -61,6 +61,12 @@ #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" @@ -2528,6 +2534,9 @@ void TcpSession::reset() bool TcpSession::setup(Packet*) { + + TcpStateHandler* tsh = new TcpStateHandler; + // FIXIT-L this it should not be necessary to reset here reset(); @@ -2544,6 +2553,14 @@ bool TcpSession::setup(Packet*) 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; } diff --git a/src/stream/tcp/tcp_syn_sent_state.cc b/src/stream/tcp/tcp_syn_sent_state.cc index a59e4b60b..503d42ab4 100644 --- a/src/stream/tcp/tcp_syn_sent_state.cc +++ b/src/stream/tcp/tcp_syn_sent_state.cc @@ -24,6 +24,10 @@ using namespace std; #include "tcp_syn_sent_state.h" +#ifdef UNIT_TEST +#include "test/catch.hpp" +#endif + TcpSynSentState::TcpSynSentState() { // TODO Auto-generated constructor stub @@ -95,3 +99,6 @@ void TcpSynSentState::rst_recv(TcpSegmentDescriptor &tcp_seg, TcpStreamTracker & default_state_action( &tcp_seg, &tracker, __func__ ); } +#ifdef UNIT_TEST + +#endif