From: Masud Hasan (mashasan) Date: Tue, 28 Jun 2022 16:55:31 +0000 (+0000) Subject: Pull request #3466: rna: allow rna to fire an event when a new netflow connection... X-Git-Tag: 3.1.33.0~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4aee4f5f30b5fff7fe53126b6df37704363a5e80;p=thirdparty%2Fsnort3.git Pull request #3466: rna: allow rna to fire an event when a new netflow connection is detected Merge in SNORT/snort3 from ~MMATIRKO/snort3:netflow_conn_events to master Squashed commit of the following: commit d5a2c8c4a6217cc3dba89a8b25efae1d72e729f5 Author: Michael Matirko Date: Tue Jun 7 13:37:12 2022 -0400 rna: allow rna to fire an event when a new netflow connection is detected --- diff --git a/src/network_inspectors/rna/rna_event_handler.cc b/src/network_inspectors/rna/rna_event_handler.cc index cc7768ea1..e01ad149c 100644 --- a/src/network_inspectors/rna/rna_event_handler.cc +++ b/src/network_inspectors/rna/rna_event_handler.cc @@ -134,7 +134,7 @@ void RnaCPEOSInfoEventHandler::handle(DataEvent& event, Flow*) 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; diff --git a/src/network_inspectors/rna/rna_event_handler.h b/src/network_inspectors/rna/rna_event_handler.h index b0ce76d50..32a82e4f8 100644 --- a/src/network_inspectors/rna/rna_event_handler.h +++ b/src/network_inspectors/rna/rna_event_handler.h @@ -162,10 +162,10 @@ private: 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; diff --git a/src/network_inspectors/rna/rna_inspector.cc b/src/network_inspectors/rna/rna_inspector.cc index ac15390b7..68ff5689e 100644 --- a/src/network_inspectors/rna/rna_inspector.cc +++ b/src/network_inspectors/rna/rna_inspector.cc @@ -107,7 +107,7 @@ bool RnaInspector::configure(SnortConfig*) 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) ); diff --git a/src/network_inspectors/rna/rna_pnd.cc b/src/network_inspectors/rna/rna_pnd.cc index c17eb935f..c9e0ff2ff 100644 --- a/src/network_inspectors/rna/rna_pnd.cc +++ b/src/network_inspectors/rna/rna_pnd.cc @@ -35,6 +35,7 @@ #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" @@ -182,10 +183,9 @@ bool RnaPnd::analyze_netflow(snort::DataEvent& event) if ( !p ) return false; - NetflowEvent* nfe = static_cast(&event); + NetFlowEvent* nfe = static_cast(&event); - if (nfe->get_create_host()) - analyze_netflow_host(nfe); + analyze_netflow_host(nfe); if (nfe->get_create_service()) analyze_netflow_service(nfe); @@ -193,7 +193,7 @@ bool RnaPnd::analyze_netflow(snort::DataEvent& event) return true; } -void RnaPnd::analyze_netflow_host(NetflowEvent* nfe) +void RnaPnd::analyze_netflow_host(NetFlowEvent* nfe) { const Packet* p = nfe->get_packet(); if ( !p ) @@ -211,7 +211,20 @@ void RnaPnd::analyze_netflow_host(NetflowEvent* nfe) 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) ) @@ -230,7 +243,7 @@ void RnaPnd::analyze_netflow_host(NetflowEvent* nfe) 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(); diff --git a/src/network_inspectors/rna/rna_pnd.h b/src/network_inspectors/rna/rna_pnd.h index ed5aca794..acb4ef650 100644 --- a/src/network_inspectors/rna/rna_pnd.h +++ b/src/network_inspectors/rna/rna_pnd.h @@ -133,8 +133,8 @@ public: 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(); diff --git a/src/pub_sub/CMakeLists.txt b/src/pub_sub/CMakeLists.txt index d00049a66..829d3187f 100644 --- a/src/pub_sub/CMakeLists.txt +++ b/src/pub_sub/CMakeLists.txt @@ -14,6 +14,7 @@ set (PUB_SUB_INCLUDES http_request_body_event.h netflow_event.h opportunistic_tls_event.h + rna_events.h sip_events.h smb_events.h ssh_events.h diff --git a/src/pub_sub/netflow_event.h b/src/pub_sub/netflow_event.h index f7ce3277a..82aa60158 100644 --- a/src/pub_sub/netflow_event.h +++ b/src/pub_sub/netflow_event.h @@ -21,17 +21,17 @@ #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) { } @@ -39,7 +39,7 @@ public: const Packet* get_packet() override { return pkt; } - const NetflowSessionRecord* get_record() + const NetFlowSessionRecord* get_record() { return record; } bool get_create_host() @@ -53,7 +53,7 @@ public: private: const Packet* pkt; - const NetflowSessionRecord* record; + const NetFlowSessionRecord* record; bool create_host; bool create_service; uint32_t serviceID = 0; diff --git a/src/pub_sub/rna_events.h b/src/pub_sub/rna_events.h new file mode 100644 index 000000000..986a44c0b --- /dev/null +++ b/src/pub_sub/rna_events.h @@ -0,0 +1,54 @@ +//-------------------------------------------------------------------------- +// 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 + +#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 diff --git a/src/service_inspectors/netflow/CMakeLists.txt b/src/service_inspectors/netflow/CMakeLists.txt index a4e0531f3..850a4a6d3 100644 --- a/src/service_inspectors/netflow/CMakeLists.txt +++ b/src/service_inspectors/netflow/CMakeLists.txt @@ -1,9 +1,13 @@ -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 ) @@ -13,4 +17,8 @@ if (STATIC_INSPECTORS) 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 diff --git a/src/service_inspectors/netflow/netflow.cc b/src/service_inspectors/netflow/netflow.cc index 0c1c2d976..4ea621185 100644 --- a/src/service_inspectors/netflow/netflow.cc +++ b/src/service_inspectors/netflow/netflow.cc @@ -39,10 +39,11 @@ #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 @@ -63,7 +64,7 @@ struct RecordStatus // ----------------------------------------------------------------------------- // temporary cache required to dump the output -typedef std::pair IpRecord; +typedef std::pair IpRecord; typedef std::vector DumpCache; static DumpCache* dump_cache = nullptr; @@ -80,7 +81,7 @@ static std::unordered_map* tcp_srv_map = 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}; @@ -105,24 +106,53 @@ static const NetflowRule* filter_record(const NetflowRules* rules, const int zon 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* 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: @@ -221,7 +251,14 @@ static bool version_9_record_update(const unsigned char* data, uint32_t unix_sec 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 ) @@ -235,7 +272,11 @@ static bool version_9_record_update(const unsigned char* data, uint32_t unix_sec 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 ) @@ -359,21 +400,21 @@ static bool version_9_record_update(const unsigned char* data, uint32_t unix_sec } 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 @@ -391,7 +432,7 @@ static bool decode_netflow_v9(const unsigned char* data, uint16_t size, 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 ) { @@ -401,12 +442,12 @@ static bool decode_netflow_v9(const unsigned char* data, uint16_t size, 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; @@ -426,7 +467,7 @@ static bool decode_netflow_v9(const unsigned char* data, uint16_t size, while( data < flowset_end && records ) { - NetflowSessionRecord record = {}; + NetFlowSessionRecord record = {}; RecordStatus record_status; bool bad_field = false; @@ -438,7 +479,7 @@ static bool decode_netflow_v9(const unsigned char* data, uint16_t size, 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 ) @@ -456,7 +497,7 @@ static bool decode_netflow_v9(const unsigned char* data, uint16_t size, } // 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--; @@ -478,8 +519,8 @@ static bool decode_netflow_v9(const unsigned char* data, uint16_t size, 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); } @@ -495,12 +536,12 @@ static bool decode_netflow_v9(const unsigned char* data, uint16_t size, // 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 tf; + const NetFlow9TemplateField* field; + std::vector 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 ) @@ -518,7 +559,7 @@ static bool decode_netflow_v9(const unsigned char* data, uint16_t size, 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); } @@ -569,16 +610,16 @@ static bool decode_netflow_v9(const unsigned char* data, uint16_t size, } 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 @@ -587,8 +628,8 @@ static bool decode_netflow_v5(const unsigned char* data, uint16_t size, 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 ) @@ -612,7 +653,7 @@ static bool decode_netflow_v5(const unsigned char* data, uint16_t size, 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 ) @@ -624,7 +665,7 @@ static bool decode_netflow_v5(const unsigned char* data, uint16_t size, 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; @@ -650,13 +691,13 @@ static bool decode_netflow_v5(const unsigned char* data, uint16_t size, 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; @@ -664,7 +705,7 @@ static bool validate_netflow(const Packet* p, const NetflowRules* p_rules) bool retval = false; // invalid packet size - if( size < sizeof(Netflow5Hdr)) + if( size < sizeof(NetFlow5Hdr)) return false; version = ntohs(*((const uint16_t *)data)); @@ -694,11 +735,11 @@ static bool validate_netflow(const Packet* p, const NetflowRules* p_rules) // 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; @@ -708,20 +749,20 @@ public: 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 & networks) @@ -770,7 +811,7 @@ static std::string to_string(const std::vector & zones) 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); @@ -779,7 +820,7 @@ static void show_device(const NetflowRule& d, bool is_exclude) 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); @@ -808,7 +849,7 @@ void NetflowInspector::show(const SnortConfig*) const } } -void NetflowInspector::stringify(std::ofstream& file_stream) +void NetFlowInspector::stringify(std::ofstream& file_stream) { std::sort(dump_cache->begin(), dump_cache->end(), IpCompare()); @@ -818,8 +859,8 @@ void NetflowInspector::stringify(std::ofstream& file_stream) 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"; @@ -859,7 +900,7 @@ void NetflowInspector::stringify(std::ofstream& file_stream) return; } -bool NetflowInspector::log_netflow_cache() +bool NetFlowInspector::log_netflow_cache() { const char* file_name = config->dump_file; @@ -889,7 +930,7 @@ bool NetflowInspector::log_netflow_cache() return true; } -NetflowInspector::NetflowInspector(const NetflowConfig* pc) +NetFlowInspector::NetFlowInspector(const NetFlowConfig* pc) { config = pc; @@ -900,7 +941,7 @@ NetflowInspector::NetflowInspector(const NetflowConfig* pc) dump_cache = new DumpCache; } - NetflowModule* mod = (NetflowModule*) ModuleManager::get_module(NETFLOW_NAME); + NetFlowModule* mod = (NetFlowModule*) ModuleManager::get_module(NETFLOW_NAME); if (mod) { @@ -909,7 +950,7 @@ NetflowInspector::NetflowInspector(const NetflowConfig* pc) } } -NetflowInspector::~NetflowInspector() +NetFlowInspector::~NetFlowInspector() { // config and cache removal if ( config ) @@ -933,7 +974,7 @@ NetflowInspector::~NetflowInspector() } } -void NetflowInspector::eval(Packet* p) +void NetFlowInspector::eval(Packet* p) { if ( !p->is_udp() or !p->dsize or !p->data or !netflow_cache ) return; @@ -942,23 +983,23 @@ void NetflowInspector::eval(Packet* p) 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 ) { @@ -970,12 +1011,12 @@ void NetflowInspector::tterm() 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(); } @@ -985,15 +1026,15 @@ void NetflowReloadSwapper::tswap() //------------------------------------------------------------------------- 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) diff --git a/src/service_inspectors/netflow/netflow_cache.cc b/src/service_inspectors/netflow/netflow_cache.cc index 3a21fc068..0252931f4 100644 --- a/src/service_inspectors/netflow/netflow_cache.cc +++ b/src/service_inspectors/netflow/netflow_cache.cc @@ -27,10 +27,10 @@ #include "netflow_cache.h" -THREAD_LOCAL NetflowCache* netflow_cache = nullptr; +THREAD_LOCAL NetFlowCache* netflow_cache = nullptr; template -LruCacheAllocNetflow::LruCacheAllocNetflow() +LruCacheAllocNetFlow::LruCacheAllocNetFlow() { lru = netflow_cache; } diff --git a/src/service_inspectors/netflow/netflow_cache.h b/src/service_inspectors/netflow/netflow_cache.h index 02f3ebae6..83c3ca9ec 100644 --- a/src/service_inspectors/netflow/netflow_cache.h +++ b/src/service_inspectors/netflow/netflow_cache.h @@ -29,28 +29,29 @@ #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 LruCacheAllocNetflow : public CacheAlloc +class LruCacheAllocNetFlow : public CacheAlloc { public: // This needs to be in every derived class: template struct rebind { - typedef LruCacheAllocNetflow other; + typedef LruCacheAllocNetFlow other; }; using CacheAlloc::lru; - LruCacheAllocNetflow(); + LruCacheAllocNetFlow(); }; template -class LruCacheLocalNetflow : public LruCacheLocal, public CacheInterface +class LruCacheLocalNetFlow : public LruCacheLocal, public CacheInterface { public: using LruLocal = LruCacheLocal; @@ -58,10 +59,10 @@ public: 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 - friend class LruCacheAllocNetflow; + friend class LruCacheAllocNetFlow; private: // Only the allocator calls this @@ -103,7 +104,7 @@ public: LruCacheLocalTemplate(const size_t sz, struct LruCacheLocalStats& st) : LruLocal(sz, st) {} - bool insert(const Key& key, std::vector& tf) + bool insert(const Key& key, std::vector& tf) { bool is_new = false; Value& entry = LruLocal::find_else_create(key, &is_new); @@ -134,14 +135,14 @@ private: } }; -// 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 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 NetFlowCache; -// Used to track Netflow version 9 Template fields +// Used to track NetFlow version 9 Template fields typedef std::pair TemplateFieldKey; -typedef LruCacheAllocTemplate TemplateAllocator; -typedef std::vector TemplateFieldValue; +typedef LruCacheAllocTemplate TemplateAllocator; +typedef std::vector TemplateFieldValue; typedef LruCacheLocalTemplate TemplateFieldCache; #endif diff --git a/src/service_inspectors/netflow/netflow_headers.h b/src/service_inspectors/netflow/netflow_headers.h index 6a18d343b..b9475d23b 100644 --- a/src/service_inspectors/netflow/netflow_headers.h +++ b/src/service_inspectors/netflow/netflow_headers.h @@ -28,7 +28,7 @@ #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, @@ -55,36 +55,10 @@ enum NetflowFieldTypes : uint16_t 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 @@ -94,7 +68,7 @@ struct Netflow5Hdr 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 @@ -118,34 +92,34 @@ struct Netflow5RecordHdr 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) {} diff --git a/src/service_inspectors/netflow/netflow_module.cc b/src/service_inspectors/netflow/netflow_module.cc index e2bcc6d2f..a73583cfe 100644 --- a/src/service_inspectors/netflow/netflow_module.cc +++ b/src/service_inspectors/netflow/netflow_module.cc @@ -101,28 +101,26 @@ static const PegInfo netflow_pegs[] = // 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") ) @@ -134,7 +132,7 @@ bool NetflowModule::begin(const char* fqn, int idx, SnortConfig*) 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") ) { @@ -150,7 +148,7 @@ bool NetflowModule::end(const char* fqn, int idx, SnortConfig*) 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(); @@ -219,7 +217,7 @@ bool NetflowModule::set(const char*, Value& v, SnortConfig*) 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; @@ -250,11 +248,11 @@ void NetflowModule::parse_service_id_file(const std::string& serv_id_file_path) } } -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; } diff --git a/src/service_inspectors/netflow/netflow_module.h b/src/service_inspectors/netflow/netflow_module.h index e905ea118..2d90e3693 100644 --- a/src/service_inspectors/netflow/netflow_module.h +++ b/src/service_inspectors/netflow/netflow_module.h @@ -41,7 +41,7 @@ struct SnortConfig; #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 { @@ -64,9 +64,9 @@ struct TemplateIpHash } }; -struct NetflowRule +struct NetFlowRule { - NetflowRule() { reset(); } + NetFlowRule() { reset(); } void reset() { networks.clear(); @@ -108,24 +108,24 @@ struct NetflowRule bool create_service = false; }; -using NetflowRuleList = std::vector; -struct NetflowRules +using NetFlowRuleList = std::vector; +struct NetFlowRules { - NetflowRuleList exclude; - NetflowRuleList include; + NetFlowRuleList exclude; + NetFlowRuleList include; }; -struct NetflowConfig +struct NetFlowConfig { - NetflowConfig() { } + NetFlowConfig() { } const char* dump_file = nullptr; - std::unordered_map device_rule_map; + std::unordered_map 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; @@ -138,14 +138,14 @@ struct NetflowStats : public LruCacheLocalStats 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; @@ -154,7 +154,7 @@ public: 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); @@ -168,8 +168,8 @@ public: { 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; }; diff --git a/src/service_inspectors/netflow/netflow_record.h b/src/service_inspectors/netflow/netflow_record.h new file mode 100644 index 000000000..bd3ec5986 --- /dev/null +++ b/src/service_inspectors/netflow/netflow_record.h @@ -0,0 +1,53 @@ +//-------------------------------------------------------------------------- +// 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 + +#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