src/network_inspectors/appid/service_plugins/test/Makefile \
src/network_inspectors/arp_spoof/Makefile \
src/network_inspectors/binder/Makefile \
+src/network_inspectors/binder/test/Makefile \
src/network_inspectors/normalize/Makefile \
src/network_inspectors/packet_capture/Makefile \
src/network_inspectors/perf_monitor/Makefile \
// client is always the first segment of the message, the consume()
// invocation for the session client will create the flow. This
// flow can in turn be used by subsequent FlowHAClient's.
- if ( !(*s_client_map)[header->client]->consume(&flow,&key,msg) )
+ if ( !(*s_client_map)[header->client]->consume(flow,&key,msg) )
{
ErrorMessage("Consuming HA Update message - error from client consume()\n");
break;
{
public:
virtual ~FlowHAClient() { }
- virtual bool consume(Flow**, FlowKey*, HAMessage*) { return false; }
+ virtual bool consume(Flow*&, FlowKey*, HAMessage*) { return false; }
virtual bool produce(Flow*, HAMessage*) { return false; }
virtual bool is_update_required(Flow*) { return false; }
virtual bool is_delete_required(Flow*) { return false; }
public:
StreamHAClient() : FlowHAClient(10, true) { }
~StreamHAClient() { }
- bool consume(Flow**, FlowKey*, HAMessage*)
+ bool consume(Flow*&, FlowKey*, HAMessage*)
{
s_stream_consume_called = true;
return true;
public:
OtherHAClient() : FlowHAClient(5, false) { }
~OtherHAClient() { }
- bool consume(Flow*, HAMessage*)
+ bool consume(Flow*&, HAMessage*)
{
s_other_consume_called = true;
return true;
#include "packet_io/active.h"
#include "target_based/snort_protocols.h"
#include "binder/bind_module.h"
+#include "binder/binder.h"
using namespace std;
Inspector* ins = get_binder();
if ( ins )
- ins->exec(0, flow);
+ ins->exec(BinderSpace::ExecOperation::HANDLE_GADGET, flow);
flow->clear_clouseau();
# add_shared_library(binder inspectors ${FILE_LIST})
#
#endif (STATIC_INSPECTORS)
+
+add_subdirectory( test )
#libbinder_la_LDFLAGS = $(AM_LDFLAGS) -export-dynamic -shared
#libbinder_la_SOURCES = $(file_list)
#endif
+
+if ENABLE_UNIT_TESTS
+SUBDIRS = test
+endif
+
//--------------------------------------------------------------------------
// binder.cc author Russ Combs <rucombs@cisco.com>
+#include "binder.h"
+
#include <vector>
using namespace std;
void get_bindings(Flow*, Stuff&);
void apply(Flow*, Stuff&);
Inspector* find_gadget(Flow*);
+ int exec_handle_gadget(void*);
+ int exec_eval_standby_flow(void*);
private:
vector<Binding*> bindings;
++bstats.packets;
}
-int Binder::exec(int, void* pv)
+int Binder::exec_handle_gadget( void* pv )
{
Flow* flow = (Flow*)pv;
Inspector* ins = find_gadget(flow);
return 0;
}
+// similar to eval(), but working on a Flow in HA Standby mode
+int Binder::exec_eval_standby_flow( void* pv )
+{
+ Flow* flow = (Flow*)pv;
+
+ Stuff stuff;
+ get_bindings(flow, stuff);
+ apply(flow, stuff);
+
+ ++bstats.verdicts[stuff.action];
+ return 0;
+}
+
+int Binder::exec(int operation, void* pv)
+{
+ switch( operation )
+ {
+ case BinderSpace::ExecOperation::HANDLE_GADGET:
+ return exec_handle_gadget( pv );
+ case BinderSpace::ExecOperation::EVAL_STANDBY_FLOW:
+ return exec_eval_standby_flow( pv );
+ default:
+ return (-1);
+ }
+}
+
//-------------------------------------------------------------------------
// implementation stuff
//-------------------------------------------------------------------------
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 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.
+//--------------------------------------------------------------------------
+
+// binder.h author Ed Borgoyn <eborgoyn@cisco.com>
+
+#ifndef BINDER_H
+#define BINDER_H
+
+namespace BinderSpace
+{
+ enum ExecOperation : int { HANDLE_GADGET, EVAL_STANDBY_FLOW };
+}
+
+#endif
+
//--------------------------------------------------------------------------
// binder.cc author Russ Combs <rucombs@cisco.com>
-#ifndef BINDER_H
-#define BINDER_H
+#ifndef BINDING_H
+#define BINDING_H
#include <string>
The implementation is not yet optimized for performance. A faster method
of searching for applicable bindings should be developed.
+The exec() method implements specialized Inspector::Binder functionality.
--- /dev/null
+set (
+ BINDER_TEST_LIBS
+ flow
+ framework
+ stream
+ stream_paf
+)
+
+add_cpputest(binder_test binder ${BINDER_TEST_LIBS})
--- /dev/null
+
+AM_DEFAULT_SOURCE_EXT = .cc
+
+check_PROGRAMS = \
+binder_test
+
+TESTS = $(check_PROGRAMS)
+
+binder_test_CPPFLAGS = @AM_CPPFLAGS@ @CPPUTEST_CPPFLAGS@
+
+binder_test_LDADD = \
+../../../flow/libflow.a \
+../../../framework/libframework.a \
+../../../stream/libstream.a \
+../../../stream/libstream_paf.a \
+@CPPUTEST_LDFLAGS@
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2016 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.
+//--------------------------------------------------------------------------
+
+// binder_test.cc author Ed Borgoyn <eborgoyn@cisco.com>
+// unit test main
+
+#include "network_inspectors/binder/binder.cc"
+#include "network_inspectors/binder/bind_module.h"
+
+#include <thread>
+#include <vector>
+
+#include "flow/flow.h"
+#include "framework/inspector.h"
+#include "managers/inspector_manager.h"
+#include "main/policy.h"
+#include "profiler/profiler.h"
+#include "stream/stream_api.h"
+#include "stream/stream_splitter.h"
+#include "utils/stats.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+
+THREAD_LOCAL SnortConfig* snort_conf = nullptr;
+THREAD_LOCAL BindStats bstats;
+static const PegInfo bind_pegs[] = { { nullptr, nullptr } };
+
+static std::vector<Binding*> s_bindings;
+
+static sfip_t s_src_ip, s_dst_ip;
+static Inspector* s_inspector;
+
+void show_stats(PegCount*, const PegInfo*, unsigned, const char*) { }
+void show_stats(PegCount*, const PegInfo*, IndexVec&, const char*) { }
+void show_stats(PegCount*, const PegInfo*, IndexVec&, const char*, FILE*) { }
+
+void sfvar_free(sfip_var_t*) {}
+int sfvar_ip_in(sfip_var_t*, const sfip_t*) { return 0; }
+SO_PUBLIC Inspector* InspectorManager::get_inspector(const char*, bool) { return s_inspector; }
+InspectorType InspectorManager::get_type(const char*) { return InspectorType::IT_BINDER; }
+Inspector* InspectorManager::get_binder() { return nullptr; }
+
+BinderModule::BinderModule() : Module("B", "B Help", nullptr, true) { }
+BinderModule::~BinderModule() { }
+ProfileStats* BinderModule::get_profile() const { return nullptr; }
+bool BinderModule::set( const char*, Value&, SnortConfig* ) { return true; }
+bool BinderModule::begin( const char*, int, SnortConfig* ) { return true; }
+bool BinderModule::end( const char*, int, SnortConfig* ) { return true; }
+
+std::vector<Binding*>& BinderModule::get_data() { return s_bindings; }
+const PegInfo* BinderModule::get_pegs() const { return bind_pegs; }
+PegCount* BinderModule::get_counts() const { return (PegCount*)&bstats; }
+
+Inspector::Inspector()
+{
+ ref_count = new unsigned[1];
+ ref_count[0] = 0;
+}
+Inspector::~Inspector()
+{
+ delete[] ref_count;
+}
+
+class MyInspector : public Inspector
+{
+ void eval(Packet*) { }
+};
+
+bool Inspector::get_buf(const char*, Packet*, InspectionBuffer&) { return false; }
+StreamSplitter* Inspector::get_splitter(bool) { return nullptr; }
+bool Inspector::likes(Packet*) { return false; }
+unsigned THREAD_LOCAL Inspector::slot = 0;
+
+void ParseError(const char*, ...) { }
+void LogMessage(const char*,...) { }
+
+void Stream::set_application_protocol_id_from_host_entry(Flow*, HostAttributeEntry const*, int) { }
+void Stream::set_splitter(Flow*, bool, class StreamSplitter*) { }
+const char* get_protocol_name(uint16_t) { return ""; }
+int16_t FindProtocolReference(const char*) { return 0; }
+void set_policies(SnortConfig*, unsigned) { }
+HostAttributeEntry* SFAT_LookupHostEntryByIP(const sfip_t*) { return nullptr; }
+
+Flow::Flow() { }
+Flow::~Flow() { }
+
+extern const BaseApi* nin_binder;
+
+TEST_GROUP(binder)
+{
+ void setup()
+ {
+ }
+ void teardown()
+ {
+ }
+};
+
+TEST(binder, exec)
+{
+ uint8_t* conf = new uint8_t[sizeof(SnortConfig)];
+ memset(conf,0,sizeof(SnortConfig));
+ snort_conf = (SnortConfig*)conf;
+ Flow* flow = new Flow;
+ constexpr size_t offset = offsetof(Flow, appDataList);
+ memset((uint8_t*)flow+offset, 0, sizeof(Flow)-offset);
+
+ s_inspector = new MyInspector();
+
+ flow->pkt_type = PktType::UDP;
+ flow->key = nullptr;
+ flow->session = nullptr;
+ flow->clouseau = nullptr;
+ flow->gadget = nullptr;
+ flow->ssn_client = nullptr;
+ flow->ssn_server = nullptr;
+ flow->key = new FlowKey;
+ ((FlowKey*)flow->key)->init(PktType::UDP, IpProtocol::UDP, &s_src_ip, (uint16_t)10, &s_dst_ip, (uint16_t)11, 0, 0, 0);
+ InspectApi* api = (InspectApi*)nin_binder;
+ CHECK(api != nullptr );
+ BinderModule* m = (BinderModule*)(api->base.mod_ctor());
+ CHECK(m != nullptr );
+ Binding* binding = new Binding;
+ binding->when.protos = (unsigned)PktType::UDP;
+ binding->use.type = "wizard";
+ binding->use.name = "wizard";
+ s_bindings.push_back(binding);
+ Binder* b = (Binder*)api->ctor(m);
+ CHECK(b != nullptr );
+ b->configure(snort_conf);
+ b->exec(BinderSpace::ExecOperation::EVAL_STANDBY_FLOW,(Flow*)flow);
+ CHECK(flow->ssn_client != nullptr);
+ CHECK(flow->ssn_server != nullptr);
+ api->dtor(b);
+ api->base.mod_dtor(m);
+ delete flow->key;
+ delete flow;
+ delete s_inspector;
+ delete[] conf;
+}
+
+int main(int argc, char** argv)
+{
+ return CommandLineTestRunner::RunAllTests(argc, argv);
+}
+
#include <thread>
#include <unordered_map>
+#include "binder/binder.h"
#include "main/snort_debug.h"
+#include "managers/inspector_manager.h"
#include "sfip/sf_ip.h"
#include "stream/stream_api.h"
return false;
}
-bool StreamHAClient::consume(Flow** flow, FlowKey* key, HAMessage* msg)
+bool StreamHAClient::consume(Flow*& flow, FlowKey* key, HAMessage* msg)
{
DebugMessage(DEBUG_HA,"StreamHAClient::consume()\n");
- assert(flow); // but *flow could be nullptr
assert(key);
assert(msg);
msg->cursor += sizeof(SessionHAContent);
// If flow is missing, we need to create a new one.
- if ( *flow == nullptr )
+ if ( flow == nullptr )
{
// A nullptr indicates that the protocol has no handler
- if ( (*flow = protocol_create_session(key)) == nullptr )
+ if ( (flow = protocol_create_session(key)) == nullptr )
return false;
- (*flow)->ha_state->clear(FlowHAState::NEW);
+ Inspector* b = InspectorManager::get_binder();
+ if ( b != nullptr )
+ b->exec(BinderSpace::ExecOperation::EVAL_STANDBY_FLOW,(void*)flow);
+ flow->ha_state->clear(FlowHAState::NEW);
int family = (hac->flags & SessionHAContent::FLAG_IP6) ? AF_INET6 : AF_INET;
if ( hac->flags & SessionHAContent::FLAG_LOW )
{
- sfip_set_raw(&((*flow)->server_ip), (*flow)->key->ip_l, family);
- sfip_set_raw(&((*flow)->client_ip), (*flow)->key->ip_h, family);
- (*flow)->server_port = (*flow)->key->port_l;
- (*flow)->client_port = (*flow)->key->port_h;
+ sfip_set_raw(&(flow->server_ip), flow->key->ip_l, family);
+ sfip_set_raw(&(flow->client_ip), flow->key->ip_h, family);
+ flow->server_port = flow->key->port_l;
+ flow->client_port = flow->key->port_h;
}
else
{
- sfip_set_raw(&((*flow)->client_ip), (*flow)->key->ip_l, family);
- sfip_set_raw(&((*flow)->server_ip), (*flow)->key->ip_h, family);
- (*flow)->client_port = (*flow)->key->port_l;
- (*flow)->server_port = (*flow)->key->port_h;
+ sfip_set_raw(&(flow->client_ip), flow->key->ip_l, family);
+ sfip_set_raw(&(flow->server_ip), flow->key->ip_h, family);
+ flow->client_port = flow->key->port_l;
+ flow->server_port = flow->key->port_h;
}
}
- (*flow)->ssn_state = hac->ssn_state;
- (*flow)->flow_state = hac->flow_state;
+ flow->ssn_state = hac->ssn_state;
+ flow->flow_state = hac->flow_state;
- if ( !(*flow)->ha_state->check_any(FlowHAState::STANDBY) )
+ if ( !flow->ha_state->check_any(FlowHAState::STANDBY) )
{
- protocol_deactivate_session(*flow);
- (*flow)->ha_state->add(FlowHAState::STANDBY);
+ protocol_deactivate_session(flow);
+ flow->ha_state->add(FlowHAState::STANDBY);
}
return true;
{
public:
StreamHAClient() : FlowHAClient(sizeof(SessionHAContent), true) { }
- bool consume(Flow**, FlowKey*, HAMessage*);
+ bool consume(Flow*&, FlowKey*, HAMessage*);
bool produce(Flow*, HAMessage*);
bool is_update_required(Flow*);
bool is_delete_required(Flow*);
#include "stream/icmp/icmp_session.h"
#include "stream/stream.h"
-void IcmpHA::delete_session(Flow*)
-{
- DebugMessage(DEBUG_HA,"IcmpHA::delete_session)\n");
-}
-
Flow* IcmpHA::create_session(FlowKey* key)
{
DebugMessage(DEBUG_HA,"IcmpHA::create_session\n");
{
public:
IcmpHA() : ProtocolHA(PktType::ICMP) { }
- void delete_session(Flow*);
Flow* create_session(FlowKey*);
private:
#include "main/snort_debug.h"
#include "stream/ip/ip_session.h"
-void IpHA::delete_session(Flow*)
-{
- DebugMessage(DEBUG_HA,"IpHA::delete_session)\n");
-}
-
Flow* IpHA::create_session(FlowKey* key)
{
DebugMessage(DEBUG_HA,"IpHA::create_session\n");
{
public:
IpHA() : ProtocolHA(PktType::IP) { }
- void delete_session(Flow*);
Flow* create_session(FlowKey*);
private:
#include "main/snort_debug.h"
#include "stream/tcp/tcp_session.h"
-void TcpHA::delete_session(Flow*)
-{
- DebugMessage(DEBUG_HA,"TcpHA::delete_session)\n");
-}
-
Flow* TcpHA::create_session(FlowKey* key)
{
DebugMessage(DEBUG_HA,"TcpHA::create_session)\n");
{
public:
TcpHA() : ProtocolHA(PktType::TCP) { }
- void delete_session(Flow*);
Flow* create_session(FlowKey*);
void deactivate_session(Flow*);
extern THREAD_LOCAL class FlowControl* flow_con;
-void UdpHA::delete_session(Flow*)
-{
- DebugMessage(DEBUG_HA,"UdpHA::delete_session\n");
-}
-
Flow* UdpHA::create_session(FlowKey* key)
{
DebugMessage(DEBUG_HA,"UdpHA::create_session\n");
{
public:
UdpHA() : ProtocolHA(PktType::UDP) { }
- void delete_session(Flow*);
Flow* create_session(FlowKey*);
private: