diff --git a/src/analyzer/Manager.cc b/src/analyzer/Manager.cc index 8911455804..32c930161b 100644 --- a/src/analyzer/Manager.cc +++ b/src/analyzer/Manager.cc @@ -66,12 +66,6 @@ Manager::Manager() Manager::~Manager() { - for ( analyzer_map_by_port::const_iterator i = analyzers_by_port_tcp.begin(); i != analyzers_by_port_tcp.end(); i++ ) - delete i->second; - - for ( analyzer_map_by_port::const_iterator i = analyzers_by_port_udp.begin(); i != analyzers_by_port_udp.end(); i++ ) - delete i->second; - // Clean up expected-connection table. while ( conns_by_timeout.size() ) { @@ -107,24 +101,16 @@ void Manager::DumpDebug() DBG_LOG(DBG_ANALYZER, " "); DBG_LOG(DBG_ANALYZER, "Analyzers by port:"); - for ( analyzer_map_by_port::const_iterator i = analyzers_by_port_tcp.begin(); i != analyzers_by_port_tcp.end(); i++ ) + if ( packet_analysis::AnalyzerPtr tcp = packet_mgr->GetAnalyzer("TCP") ) { - std::string s; - - for ( tag_set::const_iterator j = i->second->begin(); j != i->second->end(); j++ ) - s += std::string(GetComponentName(*j)) + " "; - - DBG_LOG(DBG_ANALYZER, " %d/tcp: %s", i->first, s.c_str()); + auto* ipba = static_cast(tcp.get()); + ipba->DumpPortDebug(); } - for ( analyzer_map_by_port::const_iterator i = analyzers_by_port_udp.begin(); i != analyzers_by_port_udp.end(); i++ ) + if ( packet_analysis::AnalyzerPtr udp = packet_mgr->GetAnalyzer("UDP") ) { - std::string s; - - for ( tag_set::const_iterator j = i->second->begin(); j != i->second->end(); j++ ) - s += std::string(GetComponentName(*j)) + " "; - - DBG_LOG(DBG_ANALYZER, " %d/udp: %s", i->first, s.c_str()); + auto* ipba = static_cast(udp.get()); + ipba->DumpPortDebug(); } #endif @@ -246,34 +232,38 @@ bool Manager::UnregisterAnalyzerForPort(EnumVal* val, PortVal* port) bool Manager::RegisterAnalyzerForPort(const Tag& tag, TransportProto proto, uint32_t port) { - tag_set* l = LookupPort(proto, port, true); + // TODO: this class is becoming more generic and removing a lot of the + // checks for protocols, but this part might need to stay like this. + packet_analysis::AnalyzerPtr analyzer; + if ( proto == TRANSPORT_TCP ) + analyzer = packet_mgr->GetAnalyzer("TCP"); + else if ( proto == TRANSPORT_UDP ) + analyzer = packet_mgr->GetAnalyzer("UDP"); - if ( ! l ) + if ( ! analyzer ) return false; -#ifdef DEBUG - const char* name = GetComponentName(tag).c_str(); - DBG_LOG(DBG_ANALYZER, "Registering analyzer %s for port %" PRIu32 "/%d", name, port, proto); -#endif + auto* ipba = static_cast(analyzer.get()); - l->insert(tag); - return true; + return ipba->RegisterAnalyzerForPort(tag, port); } bool Manager::UnregisterAnalyzerForPort(const Tag& tag, TransportProto proto, uint32_t port) { - tag_set* l = LookupPort(proto, port, true); + // TODO: this class is becoming more generic and removing a lot of the + // checks for protocols, but this part might need to stay like this. + packet_analysis::AnalyzerPtr analyzer; + if ( proto == TRANSPORT_TCP ) + analyzer = packet_mgr->GetAnalyzer("TCP"); + else if ( proto == TRANSPORT_UDP ) + analyzer = packet_mgr->GetAnalyzer("UDP"); - if ( ! l ) - return true; // still a "successful" unregistration + if ( ! analyzer ) + return false; -#ifdef DEBUG - const char* name = GetComponentName(tag).c_str(); - DBG_LOG(DBG_ANALYZER, "Unregistering analyzer %s for port %" PRIu32 "/%d", name, port, proto); -#endif + auto* ipba = static_cast(analyzer.get()); - l->erase(tag); - return true; + return ipba->UnregisterAnalyzerForPort(tag, port); } Analyzer* Manager::InstantiateAnalyzer(const Tag& tag, Connection* conn) @@ -315,37 +305,6 @@ Analyzer* Manager::InstantiateAnalyzer(const char* name, Connection* conn) return tag ? InstantiateAnalyzer(tag, conn) : nullptr; } -Manager::tag_set* Manager::LookupPort(TransportProto proto, uint32_t port, bool add_if_not_found) - { - analyzer_map_by_port* m = nullptr; - - switch ( proto ) { - case TRANSPORT_TCP: - m = &analyzers_by_port_tcp; - break; - - case TRANSPORT_UDP: - m = &analyzers_by_port_udp; - break; - - default: - reporter->InternalWarning("unsupported transport protocol in analyzer::Manager::LookupPort"); - return nullptr; - } - - analyzer_map_by_port::const_iterator i = m->find(port); - - if ( i != m->end() ) - return i->second; - - if ( ! add_if_not_found ) - return nullptr; - - tag_set* l = new tag_set; - m->insert(std::make_pair(port, l)); - return l; - } - void Manager::ExpireScheduledAnalyzers() { if ( ! run_state::network_time ) diff --git a/src/analyzer/Manager.h b/src/analyzer/Manager.h index 067d2d4a53..7b1ac05be4 100644 --- a/src/analyzer/Manager.h +++ b/src/analyzer/Manager.h @@ -339,16 +339,10 @@ private: friend class packet_analysis::IP::IPBasedAnalyzer; using tag_set = std::set; - using analyzer_map_by_port = std::map; - - tag_set* LookupPort(TransportProto proto, uint32_t port, bool add_if_not_found); tag_set GetScheduled(const Connection* conn); void ExpireScheduledAnalyzers(); - analyzer_map_by_port analyzers_by_port_tcp; - analyzer_map_by_port analyzers_by_port_udp; - //// Data structures to track analyzed scheduled for future connections. // The index for a scheduled connection. diff --git a/src/net_util.cc b/src/net_util.cc index 33f756aa3f..630c0c16bf 100644 --- a/src/net_util.cc +++ b/src/net_util.cc @@ -12,6 +12,18 @@ #include "zeek/IPAddr.h" #include "zeek/IP.h" +const char* transport_proto_string(TransportProto proto) + { + switch (proto) + { + case TRANSPORT_TCP: return "tcp"; + case TRANSPORT_UDP: return "udp"; + case TRANSPORT_ICMP: return "icmp"; + case TRANSPORT_UNKNOWN: + default: return "unknown"; + } + } + namespace zeek { uint16_t detail::ip4_in_cksum(const IPAddr& src, const IPAddr& dst, diff --git a/src/net_util.h b/src/net_util.h index deed0c6d77..695b7ec472 100644 --- a/src/net_util.h +++ b/src/net_util.h @@ -5,9 +5,11 @@ #include "zeek/zeek-config.h" // Define first. -typedef enum { +enum TransportProto { TRANSPORT_UNKNOWN, TRANSPORT_TCP, TRANSPORT_UDP, TRANSPORT_ICMP, -} TransportProto; +}; + +extern const char* transport_proto_string(TransportProto proto); typedef enum { IPv4, IPv6 } IPFamily; diff --git a/src/packet_analysis/protocol/icmp/ICMP.h b/src/packet_analysis/protocol/icmp/ICMP.h index 6d930a98e9..e6f6f67f3c 100644 --- a/src/packet_analysis/protocol/icmp/ICMP.h +++ b/src/packet_analysis/protocol/icmp/ICMP.h @@ -5,6 +5,7 @@ #include "zeek/packet_analysis/Analyzer.h" #include "zeek/packet_analysis/Component.h" #include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" +#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h" #include "zeek/analyzer/Analyzer.h" #include "zeek/RuleMatcher.h" diff --git a/src/packet_analysis/protocol/icmp/Plugin.cc b/src/packet_analysis/protocol/icmp/Plugin.cc index d4aa34a7c3..ffd27aed7c 100644 --- a/src/packet_analysis/protocol/icmp/Plugin.cc +++ b/src/packet_analysis/protocol/icmp/Plugin.cc @@ -3,6 +3,7 @@ #include "zeek/plugin/Plugin.h" #include "zeek/packet_analysis/Component.h" #include "zeek/packet_analysis/protocol/icmp/ICMP.h" +#include "zeek/analyzer/Component.h" namespace zeek::plugin::Zeek_ICMP { diff --git a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc index e7da71897d..8dd34e5e51 100644 --- a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc +++ b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.cc @@ -22,6 +22,8 @@ IPBasedAnalyzer::IPBasedAnalyzer(const char* name, TransportProto proto, uint32_ IPBasedAnalyzer::~IPBasedAnalyzer() { + for ( const auto& mapping : analyzers_by_port ) + delete mapping.second; } bool IPBasedAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pkt) @@ -212,9 +214,6 @@ bool IPBasedAnalyzer::BuildSessionAnalyzerTree(Connection* conn) SessionAdapter* root = MakeSessionAdapter(conn); analyzer::pia::PIA* pia = MakePIA(conn); - // TODO: temporary, can be replaced when the port lookup stuff is moved from analyzer_mgr - bool check_port = conn->ConnTransport() != TRANSPORT_ICMP; - bool scheduled = analyzer_mgr->ApplyScheduledAnalyzers(conn, false, root); // Hmm... Do we want *just* the expected analyzer, or all @@ -222,14 +221,10 @@ bool IPBasedAnalyzer::BuildSessionAnalyzerTree(Connection* conn) // the scheduled ones. if ( ! scheduled ) { // Let's see if it's a port we know. - if ( check_port && ! zeek::detail::dpd_ignore_ports ) + if ( ! analyzers_by_port.empty() && ! zeek::detail::dpd_ignore_ports ) { - // TODO: ideally this lookup would be local to the packet analyzer instead of - // calling out to the analyzer manager. This code can move once the TCP work - // is in progress so that it doesn't have to be done piecemeal. - // int resp_port = ntohs(conn->RespPort()); - std::set* ports = analyzer_mgr->LookupPort(conn->ConnTransport(), resp_port, false); + std::set* ports = LookupPort(resp_port, false); if ( ports ) { @@ -262,3 +257,63 @@ bool IPBasedAnalyzer::BuildSessionAnalyzerTree(Connection* conn) // TODO: temporary return true; } + +bool IPBasedAnalyzer::RegisterAnalyzerForPort(const analyzer::Tag& tag, uint32_t port) + { + tag_set* l = LookupPort(port, true); + + if ( ! l ) + return false; + +#ifdef DEBUG + const char* name = analyzer_mgr->GetComponentName(tag).c_str(); + DBG_LOG(DBG_ANALYZER, "Registering analyzer %s for port %" PRIu32 "/%d", name, port, transport); +#endif + + l->insert(tag); + return true; + } + +bool IPBasedAnalyzer::UnregisterAnalyzerForPort(const analyzer::Tag& tag, uint32_t port) + { + tag_set* l = LookupPort(port, true); + + if ( ! l ) + return true; // still a "successful" unregistration + +#ifdef DEBUG + const char* name = analyzer_mgr->GetComponentName(tag).c_str(); + DBG_LOG(DBG_ANALYZER, "Unregistering analyzer %s for port %" PRIu32 "/%d", name, port, transport); +#endif + + l->erase(tag); + return true; + } + +IPBasedAnalyzer::tag_set* IPBasedAnalyzer::LookupPort(uint32_t port, bool add_if_not_found) + { + analyzer_map_by_port::const_iterator i = analyzers_by_port.find(port); + + if ( i != analyzers_by_port.end() ) + return i->second; + + if ( ! add_if_not_found ) + return nullptr; + + tag_set* l = new tag_set{}; + analyzers_by_port.insert(std::make_pair(port, l)); + return l; + } + +void IPBasedAnalyzer::DumpPortDebug() + { + for ( const auto& mapping : analyzers_by_port ) + { + std::string s; + + for ( const auto& tag : *(mapping.second) ) + s += std::string(analyzer_mgr->GetComponentName(tag)) + " "; + + DBG_LOG(DBG_ANALYZER, " %d/%s: %s", mapping.first, transport_proto_string(transport), s.c_str()); + } + } diff --git a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h index 425b541377..a7b865bdad 100644 --- a/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h +++ b/src/packet_analysis/protocol/ip/IPBasedAnalyzer.h @@ -2,16 +2,18 @@ #pragma once +#include +#include + #include "zeek/packet_analysis/Analyzer.h" -#include "zeek/packet_analysis/Component.h" -#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h" -#include "zeek/analyzer/Analyzer.h" -#include "zeek/analyzer/Manager.h" +#include "zeek/analyzer/Tag.h" namespace zeek::analyzer::pia { class PIA; } namespace zeek::packet_analysis::IP { +class SessionAdapter; + /** * A base class for reuse by packet analyzers based on IP. This is used by default * by the TCP, UDP, and ICMP analyzers to reduce a large amount of duplicated code @@ -32,6 +34,33 @@ public: */ virtual bool IsReuse(double t, const u_char* pkt) { return false; } + /** + * Registers a well-known port for an analyzer. Once registered, + * connection on that port will start with a corresponding analyzer + * assigned. + * + * @param tag The analyzer's tag. + * @param port The port's number. + * @return True if successful. + */ + bool RegisterAnalyzerForPort(const analyzer::Tag& tag, uint32_t port); + + /** + * Unregisters a well-known port for an analyzer. + * + * @param tag The analyzer's tag. + * @param port The port's number. + * @param tag The analyzer's tag as an enum of script type \c + * Analyzer::Tag. + */ + bool UnregisterAnalyzerForPort(const analyzer::Tag& tag, uint32_t port); + + /** + * Dumps information about the registered session analyzers per port. + * Used by analyzer::Manager. + */ + void DumpPortDebug(); + protected: /** @@ -129,6 +158,15 @@ protected: private: + // While this is storing session analyzer tags, we store it here since packet analyzers + // are persitent objects. We can't do this in the adapters because those get created + // and destroyed for each connection. + using tag_set = std::set; + using analyzer_map_by_port = std::map; + analyzer_map_by_port analyzers_by_port; + + tag_set* LookupPort(uint32_t port, bool add_if_not_found); + /** * Creates a new Connection object from data gleaned from the current packet. * diff --git a/src/packet_analysis/protocol/tcp/Plugin.cc b/src/packet_analysis/protocol/tcp/Plugin.cc index 83b19e2cbf..a689886fe1 100644 --- a/src/packet_analysis/protocol/tcp/Plugin.cc +++ b/src/packet_analysis/protocol/tcp/Plugin.cc @@ -4,6 +4,7 @@ #include "zeek/packet_analysis/Component.h" #include "zeek/packet_analysis/protocol/tcp/TCP.h" #include "zeek/packet_analysis/protocol/tcp/TCPSessionAdapter.h" +#include "zeek/analyzer/Component.h" namespace zeek::plugin::Zeek_TCP { diff --git a/src/packet_analysis/protocol/udp/Plugin.cc b/src/packet_analysis/protocol/udp/Plugin.cc index 3ccab7b7d4..c9aee77b25 100644 --- a/src/packet_analysis/protocol/udp/Plugin.cc +++ b/src/packet_analysis/protocol/udp/Plugin.cc @@ -3,6 +3,7 @@ #include "zeek/plugin/Plugin.h" #include "zeek/packet_analysis/Component.h" #include "zeek/packet_analysis/protocol/udp/UDP.h" +#include "zeek/analyzer/Component.h" namespace zeek::plugin::Zeek_UDP { diff --git a/src/packet_analysis/protocol/udp/UDP.h b/src/packet_analysis/protocol/udp/UDP.h index 78fd0ce481..9310c89506 100644 --- a/src/packet_analysis/protocol/udp/UDP.h +++ b/src/packet_analysis/protocol/udp/UDP.h @@ -5,6 +5,7 @@ #include "zeek/packet_analysis/Analyzer.h" #include "zeek/packet_analysis/Component.h" #include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h" +#include "zeek/packet_analysis/protocol/ip/SessionAdapter.h" namespace zeek::packet_analysis::UDP {