#include "detection/detection_engine.h"
#include "flow/ha.h"
#include "flow/session.h"
+#include "framework/data_bus.h"
#include "ips_options/ips_flowbits.h"
#include "protocols/packet.h"
#include "sfip/sf_ip.h"
&& (session->missing_in_reassembled(dir) == SSN_MISSING_NONE)
&& !(ssn_state.session_flags & SSNFLAG_MIDSTREAM));
}
+
+void Flow::set_service(Packet* pkt, const char* new_service)
+{
+ service = new_service;
+ DataBus::publish(FLOW_SERVICE_CHANGE_EVENT, pkt);
+}
+
// state. Inspector state is stored in FlowData, and Flow manages a list
// of FlowData items.
+#include "framework/data_bus.h"
#include "framework/decode_data.h"
#include "framework/inspector.h"
#include "protocols/layer.h"
void set_ttl(Packet*, bool client);
void set_mpls_layer_per_dir(Packet*);
Layer get_mpls_layer_per_dir(bool);
+ void set_service(Packet* pkt, const char* new_service);
uint32_t update_session_flags(uint32_t flags)
{ return ssn_state.session_flags = flags; }
#define THREAD_IDLE_EVENT "thread.idle"
#define THREAD_ROTATE_EVENT "thread.rotate"
+// An event that indicates that the service on a flow has been updated.
+#define FLOW_SERVICE_CHANGE_EVENT "flow_service_change_event"
+
#endif
#include "flow/flow.h"
#include "flow/flow_key.h"
+#include "framework/data_bus.h"
#include "log/messages.h"
#include "main/snort_config.h"
#include "managers/inspector_manager.h"
vector<Binding*> bindings;
};
+// When a flow's service changes, re-evaluate service to inspector mapping.
+class FlowServiceChangeHandler : public DataHandler
+{
+public:
+ FlowServiceChangeHandler() { }
+
+ void handle(DataEvent&, Flow* flow) override
+ {
+ Binder* binder = (Binder*)InspectorManager::get_binder();
+ if(binder and flow)
+ binder->exec(BinderSpace::ExecOperation::HANDLE_GADGET, flow);
+ }
+};
+
Binder::Binder(vector<Binding*>& v)
{
bindings = std::move(v);
if ( !pb->use.ips_index and !pb->use.inspection_index and !pb->use.network_index )
set_binding(sc, pb);
}
+
+ DataBus::subscribe(FLOW_SERVICE_CHANGE_EVENT, new FlowServiceChangeHandler);
+
return true;
}
int Binder::exec_handle_gadget( void* pv )
{
+ assert(pv);
+
Flow* flow = (Flow*)pv;
Inspector* ins = find_gadget(flow);
of searching for applicable bindings should be developed.
The exec() method implements specialized Inspector::Binder functionality.
+
+Binder subscribes to the FLOW_SERVICE_CHANGE_EVENT and if the event
+is received, possibly due to an inspector discovering new information
+about the flow's service, then it will call Bind::exec again to reset
+the service-to-inspector mapping.
+
dce_co.h
dce_common.cc
dce_common.h
- dce_http_common.cc
- dce_http_common.h
dce_http_proxy.cc
dce_http_proxy_module.cc
dce_http_proxy_module.h
extern THREAD_LOCAL int dce2_detected;
#define GID_DCE2 133
+#define DCE_RPC_SERVICE_NAME "dcerpc"
enum DCE2_Policy
{
+++ /dev/null
-//--------------------------------------------------------------------------
-// Copyright (C) 2016-2018 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.
-//--------------------------------------------------------------------------
-
-// dce_http_common.cc author Ed Borgoyn <eborgoyn@cisco.com>
-// based on work by Todd Wease
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "dce_http_common.h"
-
-#include "binder/binder.h"
-#include "managers/inspector_manager.h"
-
-void dce_http_bind(snort::Flow* flow, const char* service)
-{
- assert (flow);
- flow->service = service;
-
- snort::Inspector* ins = snort::InspectorManager::get_binder();
-
- if ( ins )
- ins->exec(BinderSpace::ExecOperation::HANDLE_GADGET, flow);
-}
-
+++ /dev/null
-//--------------------------------------------------------------------------
-// Copyright (C) 2016-2018 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.
-//--------------------------------------------------------------------------
-
-//dce_http_common.h author Ed Borgoyn <eborgoyn@cisco.com>
-// based on work by Todd Wease
-
-#ifndef DCE_HTTP_COMMON_H
-#define DCE_HTTP_COMMON_H
-
-#include "flow/flow.h"
-
-void dce_http_bind(snort::Flow* flow, const char* service);
-
-#endif
-
#include "config.h"
#endif
-#include "dce_http_common.h"
#include "dce_http_proxy_module.h"
-#include "dce_http_proxy_splitter.h"
#include "managers/inspector_manager.h"
#include "stream/libtcp/tcp_stream_session.h"
+#include "dce_http_proxy_splitter.h"
+
using namespace snort;
THREAD_LOCAL DceHttpProxyStats dce_http_proxy_stats;
{
Flow* flow = p->flow;
- if ( flow->session != nullptr)
+ if (flow->session and flow->pkt_type == PktType::TCP)
{
if ( (flow->get_session_flags() & (SSNFLAG_ABORT_CLIENT | SSNFLAG_ABORT_SERVER)) == 0 )
{
- TcpStreamSession* session = (TcpStreamSession*)flow->session;
+ TcpStreamSession* tcp_session = (TcpStreamSession*)flow->session;
DceHttpProxySplitter* c2s_splitter =
- (DceHttpProxySplitter*)(session->get_splitter(true));
+ (DceHttpProxySplitter*)(tcp_session->get_splitter(true));
DceHttpProxySplitter* s2c_splitter =
- (DceHttpProxySplitter*)(session->get_splitter(false));
+ (DceHttpProxySplitter*)(tcp_session->get_splitter(false));
if ( c2s_splitter->cutover_inspector() && s2c_splitter->cutover_inspector() )
{
dce_http_proxy_stats.http_proxy_sessions++;
- dce_http_bind(flow, "dcerpc");
+ flow->set_service(p, DCE_RPC_SERVICE_NAME);
}
else
dce_http_proxy_stats.http_proxy_session_failures++;
#include "dce_http_proxy_splitter.h"
-#include "dce_http_common.h"
#include "dce_http_proxy_module.h"
#ifdef UNIT_TEST
#include "config.h"
#endif
-#include "dce_http_common.h"
#include "dce_http_server_module.h"
-#include "dce_http_server_splitter.h"
#include "managers/inspector_manager.h"
#include "stream/libtcp/tcp_stream_session.h"
+#include "dce_http_server_splitter.h"
+
using namespace snort;
THREAD_LOCAL DceHttpServerStats dce_http_server_stats;
{
Flow* flow = p->flow;
- if ( flow->session != nullptr)
+ if (flow->session and flow->pkt_type == PktType::TCP)
{
if ( (flow->get_session_flags() & SSNFLAG_ABORT_SERVER) == 0 )
{
- TcpStreamSession* session = (TcpStreamSession*)flow->session;
-
+ TcpStreamSession* tcp_session = (TcpStreamSession*)flow->session;
DceHttpServerSplitter* splitter =
- (DceHttpServerSplitter*)(session->get_splitter(false));
+ (DceHttpServerSplitter*)(tcp_session->get_splitter(false));
if ( splitter->cutover_inspector())
{
dce_http_server_stats.http_server_sessions++;
- dce_http_bind(flow, "dcerpc");
+ flow->set_service(p, DCE_RPC_SERVICE_NAME);
}
else
dce_http_server_stats.http_server_session_failures++;
#include "dce_http_server_splitter.h"
-#include "dce_http_common.h"
#include "dce_http_server_module.h"
#ifdef UNIT_TEST
#include "detection/detection_engine.h"
#include "utils/util.h"
+#include "dce_common.h"
#include "dce_tcp_module.h"
#include "dce_tcp_paf.h"
IT_SERVICE,
(uint16_t)PktType::PDU,
nullptr, // buffers
- "dcerpc",
+ DCE_RPC_SERVICE_NAME,
dce2_tcp_init,
nullptr, // pterm
nullptr, // tinit
IT_SERVICE,
(uint16_t)PktType::UDP,
nullptr, // buffers
- "dcerpc",
+ DCE_RPC_SERVICE_NAME,
dce2_udp_init,
nullptr, // pterm
nullptr, // tinit
void FtpDataFlowData::handle_expected(Packet* p)
{
- // FIXIT-M X This is an ugly, ugly hack, but it's the way Wizard is doing it
if (!p->flow->service)
- p->flow->service = fd_svc_name;
+ p->flow->set_service(p, fd_svc_name);
}
void FtpDataFlowData::handle_eof(Packet* p)
#include "ftpdata_splitter.h"
#include "file_api/file_flows.h"
+#include "flow/session.h"
+#include "stream/stream.h"
+
#include "ftpp_si.h"
using namespace snort;
{
if ( len )
{
- if ( len != last_seg_size )
+ if(expected_seg_size == 0)
+ {
+ // FIXIT-M: Can we do better than this guess if no MSS is specified?
+ // Malware detection won't work if expected_seg_size
+ // doesn't match the payload lengths on packets before
+ // the last packet.
+ expected_seg_size = 1448;
+
+ if(flow->session and flow->pkt_type == PktType::TCP)
+ {
+ expected_seg_size = Stream::get_mss(flow, to_server());
+ uint8_t tcp_options_len = Stream::get_tcp_options_len(flow, to_server());
+ if(expected_seg_size > tcp_options_len)
+ expected_seg_size -= tcp_options_len;
+ }
+ }
+
+ if ( len != expected_seg_size )
{
+ // Treat this as the last packet of the FTP data transfer.
set_ftp_flush_flag(flow);
- last_seg_size = len;
+ expected_seg_size = len;
restart_scan();
*fp = len;
return FLUSH;
{
min = sz + get_flush_bucket_size();
restart_scan();
- last_seg_size = 1448; // FIXIT-H base this off mss or snaplen
+ expected_seg_size = 0;
}
uint16_t min;
uint16_t segs;
uint16_t bytes;
- uint16_t last_seg_size;
+ uint16_t expected_seg_size;
void restart_scan();
};
trk->set_splitter(ss);
}
+uint16_t TcpStreamSession::get_mss(bool to_server) const
+{
+ TcpStreamTracker* trk = (to_server) ? client : server;
+
+ return trk->get_mss();
+}
+
+uint8_t TcpStreamSession::get_tcp_options_len(bool to_server) const
+{
+ TcpStreamTracker* trk = (to_server) ? client : server;
+
+ return trk->get_tcp_options_len();
+}
+
StreamSplitter* TcpStreamSession::get_splitter(bool to_server)
{
if ( to_server )
bool check_alerted(snort::Packet*, uint32_t gid, uint32_t sid) override;
int update_alert(snort::Packet*, uint32_t /*gid*/, uint32_t /*sid*/,
uint32_t /*event_id*/, uint32_t /*event_second*/) override;
+ uint16_t get_mss(bool to_server) const;
+ uint8_t get_tcp_options_len(bool to_server) const;
static void sinit();
static void sterm();
this->mss = mss;
}
+ uint8_t get_tcp_options_len() const
+ {
+ return tcp_options_len;
+ }
+
+ void set_tcp_options_len(uint8_t tcp_options_len)
+ {
+ this->tcp_options_len = tcp_options_len;
+ }
+
void cache_mac_address(TcpSegmentDescriptor&, uint8_t direction);
bool compare_mac_addresses(const uint8_t eth_addr[]);
bool mac_addr_valid = false;
uint32_t fin_final_seq = 0;
bool fin_seq_set = false; // FIXIT-M should be obviated by tcp state
- // FIXIT-L make this protected...
+ uint8_t tcp_options_len = 0;
+ // FIXIT-L make this protected...
public:
uint16_t wscale = 0; /* window scale setting */
uint16_t mss = 0; /* max segment size */
#include "utils/util.h"
#include "tcp/tcp_session.h"
+#include "libtcp/tcp_stream_session.h"
#ifdef UNIT_TEST
#include "catch/snort_catch.h"
return flow->session->are_packets_missing(dir);
}
+uint16_t Stream::get_mss(Flow* flow, bool to_server)
+{
+ assert(flow and flow->session and flow->pkt_type == PktType::TCP);
+
+ TcpStreamSession* tcp_session = (TcpStreamSession*)flow->session;
+ return tcp_session->get_mss(to_server);
+}
+
+uint8_t Stream::get_tcp_options_len(Flow* flow, bool to_server)
+{
+ assert(flow and flow->session and flow->pkt_type == PktType::TCP);
+
+ TcpStreamSession* tcp_session = (TcpStreamSession*)flow->session;
+ return tcp_session->get_tcp_options_len(to_server);
+}
+
+
#ifdef UNIT_TEST
TEST_CASE("Stream API", "[stream_api][stream]")
static void reg_xtra_data_log(LogExtraData, void*);
static uint32_t get_xtra_data_map(LogFunction*&);
+ // TCP-specific accessor methods.
+ static uint16_t get_mss(Flow*, bool to_server);
+ static uint8_t get_tcp_options_len(Flow*, bool to_server);
+
private:
static void set_ip_protocol(Flow*);
};
if ( TcpStreamTracker::TCP_CLOSED != talker->get_tcp_state() )
{
+ uint8_t tcp_options_len = tsd.get_tcph()->options_len();
+ if (tsd.is_packet_from_server())
+ server->set_tcp_options_len(tcp_options_len);
+ else
+ client->set_tcp_options_len(tcp_options_len);
+
// FIXIT-M move this to normalizer base class, handle OS_PROXY in derived class
if (config->policy != StreamPolicy::OS_PROXY)
{
char* out = out_buf;
size_t iconv_rval = iconv(convert_encoding, &in_buf, &in_bytes, &out, &out_bytes);
if (iconv_rval == (size_t)-1)
+ {
+ iconv_close(convert_encoding);
return nullptr;
+ }
*out = '\0';
*out_buf_length = (out - out_buf);