http2_inspect = { }
imap = { }
modbus = { }
+netflow = {}
normalizer = { }
pop = { }
rpc_decode = { }
{ when = { proto = 'tcp', service = 'dcerpc' }, use = { type = 'dce_tcp' } },
{ when = { proto = 'udp', service = 'dcerpc' }, use = { type = 'dce_udp' } },
+ { when = { proto = 'udp', service = 'netflow' }, use = { type = 'netflow' } },
{ when = { service = 'netbios-ssn' }, use = { type = 'dce_smb' } },
{ when = { service = 'dce_http_server' }, use = { type = 'dce_http_server' } },
'|FF FC|', '|FF FD|', '|FF FE|', '|FF FF|'
}
+
+netflow_versions =
+{
+ '|00 05|', '|00 09|'
+}
+
default_wizard =
{
spells =
{ service = 'dnp3', proto = 'tcp', client_first = true,
to_server = { '|05 64|' }, to_client = { '|05 64|' } },
+ { service = 'netflow', proto = 'udp', client_first = true,
+ to_server = netflow_versions },
+
{ service = 'http2', proto = 'tcp', client_first = true,
to_server = { '|50 52 49 20 2a 20 48 54 54 50 2f 32 2e 30 0d 0a 0d 0a 53 4d 0d 0a 0d 0a|' } },
+
--[[
{ service = 'modbus', proto = 'tcp', client_first = true,
to_server = { '??|0 0|' } },
ip_med_sweep ip_med_dist ip_hi_proto ip_hi_decoy ip_hi_sweep
ip_hi_dist icmp_low_sweep icmp_med_sweep icmp_hi_sweep
default_hi_port_scan default_med_port_scan default_low_port_scan
- default_variables
+ default_variables netflow_versions
]]
snort_whitelist_append(default_whitelist)
add_subdirectory(dns)
add_subdirectory(ftp_telnet)
add_subdirectory(gtp)
-add_subdirectory(imap)
-add_subdirectory(modbus)
add_subdirectory(http_inspect)
add_subdirectory(http2_inspect)
+add_subdirectory(imap)
+add_subdirectory(modbus)
+add_subdirectory(netflow)
add_subdirectory(pop)
add_subdirectory(rpc_decode)
+add_subdirectory(s7commplus)
add_subdirectory(sip)
add_subdirectory(smtp)
add_subdirectory(ssh)
add_subdirectory(ssl)
add_subdirectory(wizard)
-add_subdirectory(s7commplus)
if (STATIC_INSPECTORS)
set (STATIC_INSPECTOR_OBJS
$<TARGET_OBJECTS:gtp_inspect>
$<TARGET_OBJECTS:imap>
$<TARGET_OBJECTS:modbus>
+ $<TARGET_OBJECTS:netflow>
$<TARGET_OBJECTS:pop>
$<TARGET_OBJECTS:rpc_decode>
+ $<TARGET_OBJECTS:s7commplus>
$<TARGET_OBJECTS:smtp>
$<TARGET_OBJECTS:ssh>
$<TARGET_OBJECTS:wizard>
- $<TARGET_OBJECTS:s7commplus>
)
endif()
--- /dev/null
+
+set ( FILE_LIST
+ netflow.cc
+ netflow.h
+ netflow_module.cc
+ netflow_module.h
+)
+
+if (STATIC_INSPECTORS)
+ add_library( netflow OBJECT ${FILE_LIST})
+
+else (STATIC_INSPECTORS)
+ add_dynamic_module(netflow inspectors ${FILE_LIST})
+
+endif (STATIC_INSPECTORS)
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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.
+//--------------------------------------------------------------------------
+
+// netflow.cc author Ron Dempster <rdempste@cisco.com>
+// Shashikant Lad <shaslad@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "netflow.h"
+#include "netflow_module.h"
+
+#include "host_tracker/host_cache.h"
+#include "profiler/profiler.h"
+#include "protocols/packet.h"
+
+using namespace snort;
+using namespace std;
+
+THREAD_LOCAL NetflowStats netflow_stats;
+THREAD_LOCAL ProfileStats netflow_perf_stats;
+
+// -----------------------------------------------------------------------------
+// static functions
+// -----------------------------------------------------------------------------
+// FIXIT-M - keeping only few checks right now
+static bool decode_netflow_v9(const unsigned char* data, uint16_t size)
+{
+ Netflow9Hdr header;
+ const Netflow9Hdr *pheader;
+
+ if( size < sizeof(Netflow9Hdr) )
+ return false;
+
+ pheader = (const Netflow9Hdr *)data;
+ header.flow_count = ntohs(pheader->flow_count);
+
+ // Invalid header flow count
+ if( header.flow_count < NETFLOW_MIN_COUNT or header.flow_count > NETFLOW_MAX_COUNT)
+ return false;
+
+ return true;
+}
+
+static bool decode_netflow_v5(const unsigned char* data, uint16_t size)
+{
+ Netflow5Hdr header;
+ const Netflow5Hdr *pheader;
+ const Netflow5RecordHdr *precord;
+ const Netflow5RecordHdr *end;
+
+ end = (const Netflow5RecordHdr *)(data + size);
+
+ pheader = (const Netflow5Hdr *)data;
+ header.flow_count = ntohs(pheader->flow_count);
+
+ // invalid header flow count
+ if( header.flow_count < NETFLOW_MIN_COUNT or header.flow_count > NETFLOW_MAX_COUNT )
+ return false;
+
+ data += sizeof(Netflow5Hdr);
+ precord = (const Netflow5RecordHdr *)data;
+
+ // Invalid flow count
+ if ( (precord + header.flow_count) > end )
+ return false;
+
+ header.sys_uptime = ntohl(pheader->sys_uptime) / 1000;
+ header.unix_secs = ntohl(pheader->unix_secs);
+ header.unix_secs -= header.sys_uptime;
+
+ // update total records
+ netflow_stats.records += header.flow_count;
+
+ unsigned i;
+ for ( i=0; i < header.flow_count; i++, precord++ )
+ {
+
+ uint32_t first_packet = header.unix_secs + (ntohl(precord->flow_first)/1000);
+ uint32_t last_packet = header.unix_secs + (ntohl(precord->flow_last)/1000);
+
+ // invalid flow time values
+ if ( first_packet > MAX_TIME or last_packet > MAX_TIME or first_packet > last_packet )
+ return false;
+
+ }
+ return true;
+}
+
+static bool validate_netflow(const Packet* p)
+{
+ uint16_t size = p->dsize;
+ const unsigned char* data = p->data;
+ uint16_t version;
+ bool retval = false;
+
+ // invalid packet size
+ if( size < sizeof(Netflow5Hdr))
+ return false;
+
+ version = ntohs(*((const uint16_t *)data));
+
+ if( version == 5 )
+ {
+ retval = decode_netflow_v5(data, size);
+ if ( retval )
+ {
+ ++netflow_stats.packets;
+ ++netflow_stats.version_5;
+ }
+ }
+ else if (version == 9)
+ {
+ retval = decode_netflow_v9(data, size);
+ if ( retval )
+ {
+ ++netflow_stats.packets;
+ ++netflow_stats.version_9;
+ }
+ }
+
+ return retval;
+}
+
+// -----------------------------------------------------------------------------
+// non-static functions
+// -----------------------------------------------------------------------------
+
+void NetflowInspector::eval(Packet* p)
+{
+ // precondition - what we registered for
+ assert((p->is_udp() and p->dsize and p->data));
+
+ if ( ! validate_netflow(p) )
+ ++netflow_stats.invalid_netflow_pkts;
+}
+
+//-------------------------------------------------------------------------
+// api stuff
+//-------------------------------------------------------------------------
+
+static Module* netflow_mod_ctor()
+{ return new NetflowModule; }
+
+static void netflow_mod_dtor(Module* m)
+{ delete m; }
+
+static Inspector* netflow_ctor(Module* m)
+{ return new NetflowInspector((NetflowModule*)m); }
+
+static void netflow_dtor(Inspector* p)
+{ delete p; }
+
+static const InspectApi netflow_api =
+{
+ {
+ PT_INSPECTOR,
+ sizeof(InspectApi),
+ INSAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ NETFLOW_NAME,
+ NETFLOW_HELP,
+ netflow_mod_ctor,
+ netflow_mod_dtor
+ },
+ IT_SERVICE,
+ PROTO_BIT__UDP,
+ nullptr, // buffers
+ "netflow", // service
+ nullptr,
+ nullptr, //pterm
+ nullptr, // pre-config tinit
+ nullptr, // pre-config tterm
+ netflow_ctor,
+ netflow_dtor,
+ nullptr, // ssn
+ nullptr // reset
+};
+
+#ifdef BUILDING_SO
+SO_PUBLIC const BaseApi* snort_plugins[] =
+#else
+const BaseApi* sin_netflow[] =
+#endif
+{
+ &netflow_api.base,
+ nullptr
+};
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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.
+//--------------------------------------------------------------------------
+
+// netflow.h author Ron Dempster <rdempste@cisco.com>
+// Shashikant Lad <shaslad@cisco.com>
+
+#ifndef NETFLOW_H
+#define NETFLOW_H
+
+#include "flow/flow.h"
+
+namespace snort
+{
+struct Packet;
+}
+
+class NetflowModule;
+
+#define NETFLOW_MIN_COUNT 1
+#define NETFLOW_MAX_COUNT 256
+#define MAX_TIME 2145916799
+
+struct Netflow5Hdr
+{
+ uint16_t version; // Netflow export format version number
+ uint16_t flow_count; // Number of flows exported in this packet(1-30)
+ uint32_t sys_uptime; // Current time in milliseconds since the export device booted
+ uint32_t unix_secs; // Current count of seconds since 0000 UTC 1970
+ uint32_t unix_nsecs; // Residual nanoseconds since 0000 UTC 1970
+ uint32_t flow_sequence; // Sequence counter of total flows seen
+ uint8_t engine_type; // Type of flow-switching engine
+ uint8_t engine_id; // Slot number of the flow-switching engine
+ uint16_t sampling_interval; // First two bits hold the sampling mode; remaining 14 bits hold value of sampling interval
+};
+
+struct Netflow5RecordHdr
+{
+ uint32_t flow_src_addr; // Source IP address
+ uint32_t flow_dst_addr; // Destination IP address
+ uint32_t next_hop_addr; // IP address of next hop router
+ uint16_t snmp_if_in; // SNMP index of input interface
+ uint16_t snmp_if_out; // SNMP index of output interface
+ uint32_t pkt_count; // Packets in the flow
+ uint32_t bytes_sent; // Total number of Layer 3 bytes in the packets of the flow
+ uint32_t flow_first; // System uptime at start of flow
+ uint32_t flow_last; // System uptime at the time the last packet of the flow was received
+ uint16_t src_port; // TCP/UDP source port number or equivalent
+ uint16_t dst_port; // TCP/UDP destination port number or equivalent
+ uint8_t pad1; // Unused (zero) bytes
+ uint8_t tcp_flags; // Cumulative OR of TCP flags
+ uint8_t flow_protocol; // IP protocol type (for example, TCP = 6; UDP = 17)
+ uint8_t tos; // IP type of service
+ uint16_t src_as; // Autonomous system number of the source, either origin or peer
+ uint16_t dst_as; // Autonomous system number of the destination, either origin or peer
+ uint8_t src_mask; // Source address prefix mask bits
+ uint8_t dst_mask; // Destination address prefix mask bits
+ uint16_t pad2; // Unused (zero) bytes
+};
+
+struct Netflow9Hdr
+{
+ uint16_t version; // The version of netflow records exported in this packet;
+ uint16_t flow_count; // Number of FlowSet records (both template and data) contained within this packet
+ uint32_t sys_uptime; // Time in milliseconds since this device was first booted
+ uint32_t unix_secs; // Seconds since 0000 Coordinated Universal Time (UTC) 1970
+ uint32_t sequence_num; // Incremental sequence counter of all export packets sent by this export device;
+ uint32_t source_id; // A 32-bit value that identifies the Exporter Observation Domain
+};
+
+class NetflowInspector : public snort::Inspector
+{
+public:
+ NetflowInspector(NetflowModule*) {}
+ void eval(snort::Packet*) override;
+};
+
+#endif
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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.
+//--------------------------------------------------------------------------
+
+// netflow_module.cc author Shashikant Lad <shaslad@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "netflow_module.h"
+
+using namespace snort;
+
+// -----------------------------------------------------------------------------
+// static variables
+// -----------------------------------------------------------------------------
+
+static const Parameter netflow_params[] =
+{
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+static const PegInfo netflow_pegs[] =
+{
+ { CountType::SUM, "packets", "total packets processed" },
+ { CountType::SUM, "records", "total records found in netflow data" },
+ { CountType::SUM, "version_5", "count of netflow version 5 packets received" },
+ { CountType::SUM, "version_9", "count of netflow version 9 packets received" },
+ { CountType::SUM, "invalid_netflow_pkts", "count of invalid netflow packets" },
+ { CountType::END, nullptr, nullptr},
+};
+
+//-------------------------------------------------------------------------
+// netflow module
+//-------------------------------------------------------------------------
+
+NetflowModule::NetflowModule() : Module(NETFLOW_NAME, NETFLOW_HELP, netflow_params)
+{ }
+
+PegCount* NetflowModule::get_counts() const
+{ return (PegCount*)&netflow_stats; }
+
+const PegInfo* NetflowModule::get_pegs() const
+{ return netflow_pegs; }
+
+ProfileStats* NetflowModule::get_profile() const
+{ return &netflow_perf_stats; }
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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.
+//--------------------------------------------------------------------------
+
+// netflow_module.h author Shashikant Lad <shaslad@cisco.com>
+
+
+#ifndef NETFLOW_MODULE_H
+#define NETFLOW_MODULE_H
+
+#include "framework/module.h"
+
+#define NETFLOW_NAME "netflow"
+#define NETFLOW_HELP "netflow inspection"
+
+namespace snort
+{
+struct SnortConfig;
+}
+
+struct NetflowStats
+{
+ PegCount packets;
+ PegCount records;
+ PegCount version_5;
+ PegCount version_9;
+ PegCount invalid_netflow_pkts;
+};
+
+extern THREAD_LOCAL NetflowStats netflow_stats;
+extern THREAD_LOCAL snort::ProfileStats netflow_perf_stats;
+
+class NetflowModule : public snort::Module
+{
+public:
+ NetflowModule();
+
+ bool set(const char*, snort::Value&, snort::SnortConfig*) override
+ {return false; }
+
+ const PegInfo* get_pegs() const override;
+ PegCount* get_counts() const override;
+ snort::ProfileStats* get_profile() const override;
+
+ Usage get_usage() const override
+ { return INSPECT; }
+
+ bool is_bindable() const override
+ { return true; }
+};
+
+#endif
extern const BaseApi* sin_dnp3[];
extern const BaseApi* sin_gtp[];
extern const BaseApi* sin_modbus[];
+extern const BaseApi* sin_netflow[];
extern const BaseApi* sin_s7commplus[];
#endif
PluginManager::load_plugins(sin_dnp3);
PluginManager::load_plugins(sin_gtp);
PluginManager::load_plugins(sin_modbus);
+ PluginManager::load_plugins(sin_netflow);
PluginManager::load_plugins(sin_s7commplus);
#endif
}