pnd.analyze_cpe_os_info(event);
}
-void RnaNetflowEventHandler::handle(DataEvent& event, Flow*)
+void RnaNetFlowEventHandler::handle(DataEvent& event, Flow*)
{
Profile profile(rna_perf_stats);
++rna_stats.netflow_record;
RnaPnd& pnd;
};
-class RnaNetflowEventHandler : public snort::DataHandler
+class RnaNetFlowEventHandler : public snort::DataHandler
{
public:
- RnaNetflowEventHandler(RnaPnd& nd) : DataHandler(RNA_NAME), pnd(nd) { }
+ RnaNetFlowEventHandler(RnaPnd& nd) : DataHandler(RNA_NAME), pnd(nd) { }
void handle(snort::DataEvent&, snort::Flow*) override;
private:
RnaPnd& pnd;
DataBus::subscribe_network( STREAM_TCP_MIDSTREAM_EVENT, new RnaTcpMidstreamEventHandler(*pnd) );
DataBus::subscribe_network( CPE_OS_INFO_EVENT, new RnaCPEOSInfoEventHandler(*pnd) );
- DataBus::subscribe_network( NETFLOW_EVENT, new RnaNetflowEventHandler(*pnd) );
+ DataBus::subscribe_network( NETFLOW_EVENT, new RnaNetFlowEventHandler(*pnd) );
if (rna_conf && rna_conf->log_when_idle)
DataBus::subscribe_network( THREAD_IDLE_EVENT, new RnaIdleEventHandler(*pnd) );
#include "protocols/icmp4.h"
#include "protocols/icmp6.h"
#include "protocols/protocol_ids.h"
+#include "pub_sub/rna_events.h"
#include "rna_app_discovery.h"
#include "rna_cpe_os.h"
if ( !p )
return false;
- NetflowEvent* nfe = static_cast<NetflowEvent*>(&event);
+ NetFlowEvent* nfe = static_cast<NetFlowEvent*>(&event);
- if (nfe->get_create_host())
- analyze_netflow_host(nfe);
+ analyze_netflow_host(nfe);
if (nfe->get_create_service())
analyze_netflow_service(nfe);
return true;
}
-void RnaPnd::analyze_netflow_host(NetflowEvent* nfe)
+void RnaPnd::analyze_netflow_host(NetFlowEvent* nfe)
{
const Packet* p = nfe->get_packet();
if ( !p )
const uint8_t src_mac[6] = {0};
if ( new_host )
- logger.log(RNA_EVENT_NEW, NEW_HOST, p, &ht, src_ip_ptr, src_mac);
+ {
+ if (!nfe->get_create_host() and !nfe->get_create_service())
+ {
+ uint32_t service = nfe->get_service_id();
+ RNAEvent new_flow_event(p, nfe->get_record(), service);
+ DataBus::publish(RNA_NEW_NETFLOW_HOST, new_flow_event);
+ return;
+ }
+
+ if ( nfe->get_create_host() )
+ logger.log(RNA_EVENT_NEW, NEW_HOST, p, &ht, src_ip_ptr, src_mac);
+ else
+ return;
+ }
uint16_t ptype = rna_get_eth(p);
if ( ptype > to_utype(ProtocolId::ETHERTYPE_MINIMUM) )
generate_change_host_update(&ht, p, &src_ip, src_mac, packet_time());
}
-void RnaPnd::analyze_netflow_service(NetflowEvent* nfe)
+void RnaPnd::analyze_netflow_service(NetFlowEvent* nfe)
{
const Packet* p = nfe->get_packet();
void analyze_smb_fingerprint(snort::DataEvent&);
bool analyze_cpe_os_info(snort::DataEvent&);
bool analyze_netflow(snort::DataEvent&);
- void analyze_netflow_host(snort::NetflowEvent*);
- void analyze_netflow_service(snort::NetflowEvent*);
+ void analyze_netflow_host(snort::NetFlowEvent*);
+ void analyze_netflow_service(snort::NetFlowEvent*);
// generate change event for all hosts in the ip cache
void generate_change_host_update();
http_request_body_event.h
netflow_event.h
opportunistic_tls_event.h
+ rna_events.h
sip_events.h
smb_events.h
ssh_events.h
#define NETFLOW_EVENT_H
#include "framework/data_bus.h"
-#include "service_inspectors/netflow/netflow_headers.h"
+#include "service_inspectors/netflow/netflow_record.h"
#define NETFLOW_EVENT "service_inspector.netflow"
namespace snort
{
-class NetflowEvent : public DataEvent
+class NetFlowEvent : public DataEvent
{
public:
- NetflowEvent(const snort::Packet* p, const NetflowSessionRecord* rec,
+ NetFlowEvent(const snort::Packet* p, const NetFlowSessionRecord* rec,
bool cre_host, bool cre_serv, uint32_t s_id)
: pkt(p), record(rec), create_host(cre_host),
create_service(cre_serv), serviceID(s_id) { }
const Packet* get_packet() override
{ return pkt; }
- const NetflowSessionRecord* get_record()
+ const NetFlowSessionRecord* get_record()
{ return record; }
bool get_create_host()
private:
const Packet* pkt;
- const NetflowSessionRecord* record;
+ const NetFlowSessionRecord* record;
bool create_host;
bool create_service;
uint32_t serviceID = 0;
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2022-2022 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.
+//--------------------------------------------------------------------------
+// rna_events.h author Michael Matirko <mmatirko@cisco.com>
+
+#ifndef RNA_EVENTS_H
+#define RNA_EVENTS_H
+
+#include "framework/data_bus.h"
+#include "service_inspectors/netflow/netflow_record.h"
+
+#define RNA_NEW_NETFLOW_HOST "network_inspector.rna.new_netflow_host"
+
+namespace snort
+{
+
+class RNAEvent : public DataEvent
+{
+public:
+ RNAEvent(const snort::Packet* p, const NetFlowSessionRecord* rec, const uint32_t service)
+ : pkt(p), record(rec), service_id(service) { }
+
+ const Packet* get_packet() override
+ { return pkt; }
+
+ const NetFlowSessionRecord* get_record()
+ { return record; }
+
+ uint32_t get_service_id()
+ { return service_id; }
+
+private:
+ const Packet* pkt;
+ const NetFlowSessionRecord* record;
+ const uint32_t service_id;
+};
+
+}
+
+#endif
\ No newline at end of file
-set ( FILE_LIST
+set ( NETFLOW_INCLUDES
netflow_cache.h
netflow_headers.h
- netflow_module.cc
netflow_module.h
+ netflow_record.h
+)
+set ( FILE_LIST
+ ${NETFLOW_INCLUDES}
+ netflow_module.cc
netflow.cc
)
else (STATIC_INSPECTORS)
add_dynamic_module(netflow inspectors ${FILE_LIST})
-endif (STATIC_INSPECTORS)
\ No newline at end of file
+endif (STATIC_INSPECTORS)
+
+install(FILES ${NETFLOW_INCLUDES}
+ DESTINATION "${INCLUDE_INSTALL_PATH}/service_inspectors/netflow"
+)
\ No newline at end of file
#include "utils/util.h"
#include "netflow_cache.cc"
+#include "netflow_record.h"
using namespace snort;
-THREAD_LOCAL NetflowStats netflow_stats;
+THREAD_LOCAL NetFlowStats netflow_stats;
THREAD_LOCAL ProfileStats netflow_perf_stats;
// Used to ensure we fully populate the record; can't rely on the actual values being zero
// -----------------------------------------------------------------------------
// temporary cache required to dump the output
-typedef std::pair<snort::SfIp, NetflowSessionRecord> IpRecord;
+typedef std::pair<snort::SfIp, NetFlowSessionRecord> IpRecord;
typedef std::vector<IpRecord> DumpCache;
static DumpCache* dump_cache = nullptr;
// -----------------------------------------------------------------------------
// static functions
// -----------------------------------------------------------------------------
-static const NetflowRule* filter_record(const NetflowRules* rules, const int zone,
+static const NetFlowRule* filter_record(const NetFlowRules* rules, const int zone,
const SfIp* src, const SfIp* dst)
{
const SfIp* addr[2] = {src, dst};
return nullptr;
}
-static void publish_service_event(const Packet* p, const NetflowRule* match, NetflowSessionRecord& record)
+static void publish_netflow_event(const Packet* p, const NetFlowRule* match, NetFlowSessionRecord& record)
{
uint32_t serviceID = 0;
+ std::unordered_map<int, int>* service_mappings = nullptr;
+
if (record.proto == (int) ProtocolId::TCP and tcp_srv_map)
- serviceID = (*tcp_srv_map)[record.responder_port];
+ service_mappings = tcp_srv_map;
else if (record.proto == (int) ProtocolId::UDP and udp_srv_map)
- serviceID = (*udp_srv_map)[record.responder_port];
+ service_mappings = udp_srv_map;
+
+ if (service_mappings)
+ {
+ uint32_t sid_responder;
+ uint32_t sid_initiator;
+
+ if (service_mappings->count(record.responder_port))
+ sid_responder = (*service_mappings)[record.responder_port];
+ else
+ sid_responder = 0;
+
+ if (service_mappings->count(record.initiator_port))
+ sid_initiator = (*service_mappings)[record.initiator_port];
+ else
+ sid_initiator = 0;
- NetflowEvent event(p, &record, match->create_host, match->create_service, serviceID);
+ // Use only the known port. If both are known, take the lower numbered port.
+ if (sid_responder && !sid_initiator)
+ serviceID = sid_responder;
+ else if (sid_initiator && !sid_responder)
+ serviceID = sid_initiator;
+ else
+ serviceID = (record.initiator_port > record.responder_port) ? sid_responder : sid_initiator;
+ }
+
+ NetFlowEvent event(p, &record, match->create_host, match->create_service, serviceID);
DataBus::publish(NETFLOW_EVENT, event);
}
static bool version_9_record_update(const unsigned char* data, uint32_t unix_secs,
- uint16_t field_type, uint16_t field_length, NetflowSessionRecord &record,
- RecordStatus& record_status)
+ uint32_t sys_uptime, uint16_t field_type, uint16_t field_length,
+ NetFlowSessionRecord &record, RecordStatus& record_status)
{
+ uint32_t last_pkt_time = 0;
+ uint32_t first_pkt_time = 0;
+
switch ( field_type )
{
case NETFLOW_PROTOCOL:
if( field_length != sizeof(record.last_pkt_second) )
return false;
- record.last_pkt_second = unix_secs + ntohl(*(const time_t*)data)/1000;
+ last_pkt_time = ntohl(*(const time_t*)data)/1000;
+ // last_pkt_time (LAST_SWITCHED) is defined as the system uptime
+ // at which the flow was seen. If this is == to the current uptime
+ // something has gone wrong - use the NetFlow header unix time instead.
+ if (last_pkt_time >= sys_uptime)
+ record.last_pkt_second = unix_secs;
+ else
+ record.last_pkt_second = unix_secs + last_pkt_time;
// invalid flow time value
if( record.last_pkt_second > MAX_TIME )
if( field_length != sizeof(record.first_pkt_second) )
return false;
- record.first_pkt_second = unix_secs + ntohl(*(const time_t*)data)/1000;
+ first_pkt_time = ntohl(*(const time_t*)data)/1000;
+ if (first_pkt_time >= sys_uptime)
+ record.first_pkt_second = unix_secs;
+ else
+ record.first_pkt_second = unix_secs + first_pkt_time;
// invalid flow time value
if( record.first_pkt_second > MAX_TIME )
}
static bool decode_netflow_v9(const unsigned char* data, uint16_t size,
- const Packet* p, const NetflowRules* p_rules)
+ const Packet* p, const NetFlowRules* p_rules)
{
- Netflow9Hdr header;
- const Netflow9Hdr *pheader;
- const Netflow9FlowSet *flowset;
+ NetFlow9Hdr header;
+ const NetFlow9Hdr *pheader;
+ const NetFlow9FlowSet *flowset;
const uint8_t *end;
const uint8_t *flowset_end;
uint16_t records;
- if( size < sizeof(Netflow9Hdr) )
+ if( size < sizeof(NetFlow9Hdr) )
return false;
end = data + size;
- pheader = (const Netflow9Hdr *)data;
+ pheader = (const NetFlow9Hdr *)data;
header.flow_count = ntohs(pheader->flow_count);
// invalid header flow count
const int zone = p->pkth->ingress_index;
const snort::SfIp device_ip = *p->ptrs.ip_api.get_src();
- data += sizeof(Netflow9Hdr);
+ data += sizeof(NetFlow9Hdr);
while ( data < end )
{
if ( data + sizeof(*flowset) > end )
return false;
- flowset = (const Netflow9FlowSet *)data;
+ flowset = (const NetFlow9FlowSet *)data;
// length includes the flowset_id and length fields
length = ntohs(flowset->field_length);
- // invalid Netflow length
+ // invalid NetFlow length
if( data + length > end )
return false;
while( data < flowset_end && records )
{
- NetflowSessionRecord record = {};
+ NetFlowSessionRecord record = {};
RecordStatus record_status;
bool bad_field = false;
if ( !bad_field )
{
- bool status = version_9_record_update(data, header.unix_secs,
+ bool status = version_9_record_update(data, header.unix_secs, header.sys_uptime,
t_field->field_type, t_field->field_length, record, record_status);
if ( !status )
}
// filter based on configuration
- const NetflowRule* match = filter_record(p_rules, zone, &record.initiator_ip, &record.responder_ip);
+ const NetFlowRule* match = filter_record(p_rules, zone, &record.initiator_ip, &record.responder_ip);
if ( !match )
{
records--;
record.nf_src_tos = record.nf_dst_tos;
}
- if (match->create_service)
- publish_service_event(p, match, record);
+ record.netflow_initiator_ip.set(p->ptrs.ip_api.get_src()->get_ip6_ptr(), AF_INET6);
+ publish_netflow_event(p, match, record);
}
// Step through the templates in this flowset and store them
while ( data < flowset_end && records )
{
- const Netflow9Template* t_template;
+ const NetFlow9Template* t_template;
uint16_t field_count, t_id;
- const Netflow9TemplateField* field;
- std::vector<Netflow9TemplateField> tf;
+ const NetFlow9TemplateField* field;
+ std::vector<NetFlow9TemplateField> tf;
- t_template = (const Netflow9Template *)data;
+ t_template = (const NetFlow9Template *)data;
field_count = ntohs(t_template->template_field_count);
if ( data + sizeof(*t_template) > flowset_end )
if ( data + sizeof(*field) > flowset_end )
return false;
- field = (const Netflow9TemplateField *)data;
+ field = (const NetFlow9TemplateField *)data;
tf.emplace_back(ntohs(field->field_type), ntohs(field->field_length));
data += sizeof(*field);
}
}
static bool decode_netflow_v5(const unsigned char* data, uint16_t size,
- const Packet* p, const NetflowRules* p_rules)
+ const Packet* p, const NetFlowRules* p_rules)
{
- Netflow5Hdr header;
- const Netflow5Hdr *pheader;
- const Netflow5RecordHdr *precord;
- const Netflow5RecordHdr *end;
+ NetFlow5Hdr header;
+ const NetFlow5Hdr *pheader;
+ const NetFlow5RecordHdr *precord;
+ const NetFlow5RecordHdr *end;
- end = (const Netflow5RecordHdr *)(data + size);
+ end = (const NetFlow5RecordHdr *)(data + size);
- pheader = (const Netflow5Hdr *)data;
+ pheader = (const NetFlow5Hdr *)data;
header.flow_count = ntohs(pheader->flow_count);
// invalid header flow count
const int zone = p->pkth->ingress_index;
- data += sizeof(Netflow5Hdr);
- precord = (const Netflow5RecordHdr *)data;
+ data += sizeof(NetFlow5Hdr);
+ precord = (const NetFlow5RecordHdr *)data;
// Invalid flow count
if ( (precord + header.flow_count) > end )
if ( first_packet > MAX_TIME or last_packet > MAX_TIME or first_packet > last_packet )
return false;
- NetflowSessionRecord record = {};
+ NetFlowSessionRecord record = {};
// Invalid source IP address provided
if ( record.initiator_ip.set(&precord->flow_src_addr, AF_INET) != SFIP_SUCCESS )
if ( record.next_hop_ip.set(&precord->next_hop_addr, AF_INET) != SFIP_SUCCESS )
return false;
- const NetflowRule* match = filter_record(p_rules, zone, &record.initiator_ip, &record.responder_ip);
+ const NetFlowRule* match = filter_record(p_rules, zone, &record.initiator_ip, &record.responder_ip);
if ( !match )
continue;
if ( netflow_cache->add(record.initiator_ip, record, false) )
++netflow_stats.unique_flows;
- if (match->create_service)
- publish_service_event(p, match, record);
+ record.netflow_initiator_ip.set(p->ptrs.ip_api.get_src()->get_ip6_ptr(), AF_INET6);
+ publish_netflow_event(p, match, record);
}
return true;
}
-static bool validate_netflow(const Packet* p, const NetflowRules* p_rules)
+static bool validate_netflow(const Packet* p, const NetFlowRules* p_rules)
{
uint16_t size = p->dsize;
const unsigned char* data = p->data;
bool retval = false;
// invalid packet size
- if( size < sizeof(Netflow5Hdr))
+ if( size < sizeof(NetFlow5Hdr))
return false;
version = ntohs(*((const uint16_t *)data));
// inspector stuff
//-------------------------------------------------------------------------
-class NetflowInspector : public snort::Inspector
+class NetFlowInspector : public snort::Inspector
{
public:
- NetflowInspector(const NetflowConfig*);
- ~NetflowInspector() override;
+ NetFlowInspector(const NetFlowConfig*);
+ ~NetFlowInspector() override;
void tinit() override;
void tterm() override;
void install_reload_handler(snort::SnortConfig*) override;
private:
- const NetflowConfig *config;
+ const NetFlowConfig *config;
bool log_netflow_cache();
void stringify(std::ofstream&);
};
-class NetflowReloadSwapper : public snort::ReloadSwapper
+class NetFlowReloadSwapper : public snort::ReloadSwapper
{
public:
- explicit NetflowReloadSwapper(NetflowInspector& ins) : inspector(ins) { }
+ explicit NetFlowReloadSwapper(NetFlowInspector& ins) : inspector(ins) { }
void tswap() override;
private:
- NetflowInspector& inspector;
+ NetFlowInspector& inspector;
};
static std::string to_string(const std::vector <snort::SfCidr>& networks)
return zs;
}
-static void show_device(const NetflowRule& d, bool is_exclude)
+static void show_device(const NetFlowRule& d, bool is_exclude)
{
ConfigLogger::log_flag("exclude", is_exclude, true);
ConfigLogger::log_flag("create_host", d.create_host, true);
ConfigLogger::log_value("zones", to_string(d.zones).c_str(), true);
}
-void NetflowInspector::show(const SnortConfig*) const
+void NetFlowInspector::show(const SnortConfig*) const
{
ConfigLogger::log_value("flow_memcap", (uint64_t)config->flow_memcap);
ConfigLogger::log_value("template_memcap", (uint64_t)config->template_memcap);
}
}
-void NetflowInspector::stringify(std::ofstream& file_stream)
+void NetFlowInspector::stringify(std::ofstream& file_stream)
{
std::sort(dump_cache->begin(), dump_cache->end(), IpCompare());
for (auto& elem : *dump_cache)
{
- NetflowSessionRecord& record = elem.second;
- str = "Netflow Record #";
+ NetFlowSessionRecord& record = elem.second;
+ str = "NetFlow Record #";
str += std::to_string(++i);
str += "\n";
return;
}
-bool NetflowInspector::log_netflow_cache()
+bool NetFlowInspector::log_netflow_cache()
{
const char* file_name = config->dump_file;
return true;
}
-NetflowInspector::NetflowInspector(const NetflowConfig* pc)
+NetFlowInspector::NetFlowInspector(const NetFlowConfig* pc)
{
config = pc;
dump_cache = new DumpCache;
}
- NetflowModule* mod = (NetflowModule*) ModuleManager::get_module(NETFLOW_NAME);
+ NetFlowModule* mod = (NetFlowModule*) ModuleManager::get_module(NETFLOW_NAME);
if (mod)
{
}
}
-NetflowInspector::~NetflowInspector()
+NetFlowInspector::~NetFlowInspector()
{
// config and cache removal
if ( config )
}
}
-void NetflowInspector::eval(Packet* p)
+void NetFlowInspector::eval(Packet* p)
{
if ( !p->is_udp() or !p->dsize or !p->data or !netflow_cache )
return;
if ( d != config->device_rule_map.end() )
{
- const NetflowRules* p_rules = &(d->second);
+ const NetFlowRules* p_rules = &(d->second);
if ( ! validate_netflow(p, p_rules) )
++netflow_stats.invalid_netflow_record;
}
}
-void NetflowInspector::tinit()
+void NetFlowInspector::tinit()
{
delete netflow_cache;
- netflow_cache = new NetflowCache(config->flow_memcap, netflow_stats);
+ netflow_cache = new NetFlowCache(config->flow_memcap, netflow_stats);
delete template_cache;
template_cache = new TemplateFieldCache(config->template_memcap, netflow_stats);
}
-void NetflowInspector::tterm()
+void NetFlowInspector::tterm()
{
if ( config->dump_file and dump_cache )
{
delete template_cache;
}
-void NetflowInspector::install_reload_handler(SnortConfig* sc)
+void NetFlowInspector::install_reload_handler(SnortConfig* sc)
{
- sc->register_reload_handler(new NetflowReloadSwapper(*this));
+ sc->register_reload_handler(new NetFlowReloadSwapper(*this));
}
-void NetflowReloadSwapper::tswap()
+void NetFlowReloadSwapper::tswap()
{
inspector.tinit();
}
//-------------------------------------------------------------------------
static Module* netflow_mod_ctor()
-{ return new NetflowModule; }
+{ return new NetFlowModule; }
static void netflow_mod_dtor(Module* m)
{ delete m; }
static Inspector* netflow_ctor(Module* m)
{
- NetflowModule *mod = (NetflowModule*)m;
- return new NetflowInspector(mod->get_data());
+ NetFlowModule *mod = (NetFlowModule*)m;
+ return new NetFlowInspector(mod->get_data());
}
static void netflow_dtor(Inspector* p)
#include "netflow_cache.h"
-THREAD_LOCAL NetflowCache* netflow_cache = nullptr;
+THREAD_LOCAL NetFlowCache* netflow_cache = nullptr;
template <class T>
-LruCacheAllocNetflow<T>::LruCacheAllocNetflow()
+LruCacheAllocNetFlow<T>::LruCacheAllocNetFlow()
{
lru = netflow_cache;
}
#include "netflow_headers.h"
#include "netflow_module.h"
+#include "netflow_record.h"
-// Trivial derived allocator, pointing to their own cache. LruCacheAllocNetflow has a
+// Trivial derived allocator, pointing to their own cache. LruCacheAllocNetFlow has a
// CacheInterface* pointing to an lru cache. We can create different cache types by
// instantiating the lru cache using different keys and derive here allocators with
// CacheInterface* pointing to the appropriate lru cache object.
template <class T>
-class LruCacheAllocNetflow : public CacheAlloc<T>
+class LruCacheAllocNetFlow : public CacheAlloc<T>
{
public:
// This needs to be in every derived class:
template <class U>
struct rebind
{
- typedef LruCacheAllocNetflow<U> other;
+ typedef LruCacheAllocNetFlow<U> other;
};
using CacheAlloc<T>::lru;
- LruCacheAllocNetflow();
+ LruCacheAllocNetFlow();
};
template<typename Key, typename Value, typename Hash>
-class LruCacheLocalNetflow : public LruCacheLocal<Key, Value, Hash>, public CacheInterface
+class LruCacheLocalNetFlow : public LruCacheLocal<Key, Value, Hash>, public CacheInterface
{
public:
using LruLocal = LruCacheLocal<Key, Value, Hash>;
using LruLocal::max_size;
using LruLocal::list;
- LruCacheLocalNetflow(const size_t sz, struct LruCacheLocalStats& st) : LruLocal(sz, st) {}
+ LruCacheLocalNetFlow(const size_t sz, struct LruCacheLocalStats& st) : LruLocal(sz, st) {}
template <class T>
- friend class LruCacheAllocNetflow;
+ friend class LruCacheAllocNetFlow;
private:
// Only the allocator calls this
LruCacheLocalTemplate(const size_t sz, struct LruCacheLocalStats& st) : LruLocal(sz, st)
{}
- bool insert(const Key& key, std::vector<Netflow9TemplateField>& tf)
+ bool insert(const Key& key, std::vector<NetFlow9TemplateField>& tf)
{
bool is_new = false;
Value& entry = LruLocal::find_else_create(key, &is_new);
}
};
-// Used to track record for unique IP; we assume Netflow packets coming from
-// a given Netflow device will go to the same thread
-typedef LruCacheLocalNetflow<snort::SfIp, NetflowSessionRecord, NetflowHash> NetflowCache;
+// Used to track record for unique IP; we assume NetFlow packets coming from
+// a given NetFlow device will go to the same thread
+typedef LruCacheLocalNetFlow<snort::SfIp, NetFlowSessionRecord, NetFlowHash> NetFlowCache;
-// Used to track Netflow version 9 Template fields
+// Used to track NetFlow version 9 Template fields
typedef std::pair<uint16_t, snort::SfIp> TemplateFieldKey;
-typedef LruCacheAllocTemplate<Netflow9TemplateField> TemplateAllocator;
-typedef std::vector<Netflow9TemplateField, TemplateAllocator> TemplateFieldValue;
+typedef LruCacheAllocTemplate<NetFlow9TemplateField> TemplateAllocator;
+typedef std::vector<NetFlow9TemplateField, TemplateAllocator> TemplateFieldValue;
typedef LruCacheLocalTemplate<TemplateFieldKey, TemplateFieldValue, TemplateIpHash> TemplateFieldCache;
#endif
#define NETFLOW_MAX_COUNT 256
#define MAX_TIME 2145916799
-enum NetflowFieldTypes : uint16_t
+enum NetFlowFieldTypes : uint16_t
{
NETFLOW_IN_BYTES = 1,
NETFLOW_IN_PKTS = 2,
NETFLOW_DST_TOS = 55,
};
-struct NetflowSessionRecord
+struct NetFlow5Hdr
{
- snort::SfIp initiator_ip;
- snort::SfIp responder_ip;
- snort::SfIp next_hop_ip;
- uint8_t proto;
- uint16_t initiator_port;
- uint16_t responder_port;
- uint32_t first_pkt_second;
- uint32_t last_pkt_second;
- uint64_t initiator_pkts;
- uint64_t responder_pkts;
- uint64_t initiator_bytes;
- uint64_t responder_bytes;
- uint8_t tcp_flags;
-
- uint32_t nf_src_as;
- uint32_t nf_dst_as;
- uint32_t nf_snmp_in;
- uint32_t nf_snmp_out;
- uint8_t nf_src_tos;
- uint8_t nf_dst_tos;
- uint8_t nf_src_mask;
- uint8_t nf_dst_mask;
-};
-
-struct Netflow5Hdr
-{
- uint16_t version; // Netflow export format version number
- uint16_t flow_count; // Number of flows exported in this packet(1-30)
+ 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
uint16_t sampling_interval; // First two bits hold the sampling mode; remaining 14 bits hold value of sampling interval
};
-struct Netflow5RecordHdr
+struct NetFlow5RecordHdr
{
uint32_t flow_src_addr; // Source IP address
uint32_t flow_dst_addr; // Destination IP address
uint16_t pad2; // Unused (zero) bytes
};
-struct Netflow9Hdr
+struct NetFlow9Hdr
{
- uint16_t version; // The version of netflow records exported in this packet;
+ 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 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
};
-struct Netflow9FlowSet
+struct NetFlow9FlowSet
{
uint16_t field_id;
uint16_t field_length;
};
-struct Netflow9Template
+struct NetFlow9Template
{
uint16_t template_id;
uint16_t template_field_count;
};
-struct Netflow9TemplateField
+struct NetFlow9TemplateField
{
uint16_t field_type;
uint16_t field_length;
- Netflow9TemplateField(uint16_t type, uint16_t length)
+ NetFlow9TemplateField(uint16_t type, uint16_t length)
: field_type(type)
, field_length(length)
{}
// netflow module
//-------------------------------------------------------------------------
-NetflowModule::NetflowModule() : Module(NETFLOW_NAME, NETFLOW_HELP, netflow_params)
-{
- conf = nullptr;
-}
+NetFlowModule::NetFlowModule() : Module(NETFLOW_NAME, NETFLOW_HELP, netflow_params)
+{ }
-NetflowModule::~NetflowModule()
+NetFlowModule::~NetFlowModule()
{
delete conf;
}
-NetflowConfig* NetflowModule::get_data()
+NetFlowConfig* NetFlowModule::get_data()
{
- NetflowConfig* tmp = conf;
+ NetFlowConfig* tmp = conf;
conf = nullptr;
return tmp;
}
-bool NetflowModule::begin(const char* fqn, int idx, SnortConfig*)
+bool NetFlowModule::begin(const char* fqn, int idx, SnortConfig*)
{
if ( !conf )
{
- conf = new NetflowConfig();
+ conf = new NetFlowConfig();
}
if ( idx && !strcmp(fqn, "netflow.rules") )
return true;
}
-bool NetflowModule::end(const char* fqn, int idx, SnortConfig*)
+bool NetFlowModule::end(const char* fqn, int idx, SnortConfig*)
{
if ( idx && !strcmp(fqn, "netflow.rules") )
{
return true;
}
-bool NetflowModule::set(const char*, Value& v, SnortConfig*)
+bool NetFlowModule::set(const char*, Value& v, SnortConfig*)
{
if ( v.is("flow_memcap") )
conf->flow_memcap = v.get_size();
return true;
}
-void NetflowModule::parse_service_id_file(const std::string& serv_id_file_path)
+void NetFlowModule::parse_service_id_file(const std::string& serv_id_file_path)
{
std::string serv_line;
std::ifstream serv_id_file;
}
}
-PegCount* NetflowModule::get_counts() const
+PegCount* NetFlowModule::get_counts() const
{ return (PegCount*)&netflow_stats; }
-const PegInfo* NetflowModule::get_pegs() const
+const PegInfo* NetFlowModule::get_pegs() const
{ return netflow_pegs; }
-ProfileStats* NetflowModule::get_profile() const
+ProfileStats* NetFlowModule::get_profile() const
{ return &netflow_perf_stats; }
#define NETFLOW_ANY_ZONE (-1)
// Used to create hash of key for indexing into cache.
-struct NetflowHash
+struct NetFlowHash
{
size_t operator()(const snort::SfIp& ip) const
{
}
};
-struct NetflowRule
+struct NetFlowRule
{
- NetflowRule() { reset(); }
+ NetFlowRule() { reset(); }
void reset()
{
networks.clear();
bool create_service = false;
};
-using NetflowRuleList = std::vector<NetflowRule>;
-struct NetflowRules
+using NetFlowRuleList = std::vector<NetFlowRule>;
+struct NetFlowRules
{
- NetflowRuleList exclude;
- NetflowRuleList include;
+ NetFlowRuleList exclude;
+ NetFlowRuleList include;
};
-struct NetflowConfig
+struct NetFlowConfig
{
- NetflowConfig() { }
+ NetFlowConfig() { }
const char* dump_file = nullptr;
- std::unordered_map <snort::SfIp, NetflowRules, NetflowHash> device_rule_map;
+ std::unordered_map <snort::SfIp, NetFlowRules, NetFlowHash> device_rule_map;
uint32_t update_timeout = 0;
size_t flow_memcap = 0;
size_t template_memcap = 0;
};
-struct NetflowStats : public LruCacheLocalStats
+struct NetFlowStats : public LruCacheLocalStats
{
PegCount invalid_netflow_record;
PegCount packets;
PegCount version_9;
};
-extern THREAD_LOCAL NetflowStats netflow_stats;
+extern THREAD_LOCAL NetFlowStats netflow_stats;
extern THREAD_LOCAL snort::ProfileStats netflow_perf_stats;
-class NetflowModule : public snort::Module
+class NetFlowModule : public snort::Module
{
public:
- NetflowModule();
- ~NetflowModule() override;
+ NetFlowModule();
+ ~NetFlowModule() override;
bool set(const char*, snort::Value&, snort::SnortConfig*) override;
bool begin(const char*, int, snort::SnortConfig*) override;
const PegInfo* get_pegs() const override;
PegCount* get_counts() const override;
snort::ProfileStats* get_profile() const override;
- NetflowConfig* get_data();
+ NetFlowConfig* get_data();
void parse_service_id_file(const std::string& serv_id_file_path);
{ return true; }
private:
- NetflowConfig* conf = nullptr;
- NetflowRule rule_cfg = {};
+ NetFlowConfig* conf = nullptr;
+ NetFlowRule rule_cfg = {};
snort::SfIp device_ip_cfg = {};
bool is_exclude_rule = false;
};
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2022-2022 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_record.h author Michael Matirko <mmatirkoe@cisco.com>
+
+#ifndef NETFLOW_RECORD_H
+#define NETFLOW_RECORD_H
+
+#include "sfip/sf_ip.h"
+
+struct NetFlowSessionRecord
+{
+ snort::SfIp initiator_ip;
+ snort::SfIp responder_ip;
+ snort::SfIp next_hop_ip;
+ snort::SfIp netflow_initiator_ip;
+ uint8_t proto;
+ uint16_t initiator_port;
+ uint16_t responder_port;
+ uint32_t first_pkt_second;
+ uint32_t last_pkt_second;
+ uint64_t initiator_pkts;
+ uint64_t responder_pkts;
+ uint64_t initiator_bytes;
+ uint64_t responder_bytes;
+ uint8_t tcp_flags;
+
+ uint32_t nf_src_as;
+ uint32_t nf_dst_as;
+ uint32_t nf_snmp_in;
+ uint32_t nf_snmp_out;
+ uint8_t nf_src_tos;
+ uint8_t nf_dst_tos;
+ uint8_t nf_src_mask;
+ uint8_t nf_dst_mask;
+};
+
+#endif