// See the file "COPYING" in the main distribution directory for copyright. /** * The central management unit for registering and instantiating analyzers. * * For each protocol that Zeek supports, there's one class derived from * analyzer::Analyzer. Once we have decided that a connection's payload is to * be parsed as a given protocol, we instantiate the corresponding * analyzer-derived class and add the new instance as a child node into the * connection's analyzer tree. * * In addition to the analyzer-derived class itself, for each protocol * there's also "meta-class" derived from analyzer::Component that describes * the analyzer, including status information on if that particular protocol * analysis is currently enabled. * * To identify an analyzer (or to be precise: a component), the manager * maintains mappings of (1) analyzer::Tag to component, and (2) * human-readable analyzer name to component. */ #pragma once #include #include #include "zeek/IP.h" #include "zeek/Tag.h" #include "zeek/analyzer/Analyzer.h" #include "zeek/analyzer/Component.h" #include "zeek/analyzer/analyzer.bif.h" #include "zeek/net_util.h" #include "zeek/plugin/ComponentManager.h" namespace zeek { namespace packet_analysis::IP { class IPBasedAnalyzer; class SessionAdapter; } // namespace packet_analysis::IP namespace analyzer { /** * Class maintaining and scheduling available protocol analyzers. * * The manager maintains a registry of all available protocol analyzers, * including a mapping between their textual names and Tag. It * instantiates new analyzers on demand. For new connections, the manager * sets up their initial analyzer tree, including adding the right \c PIA, * respecting well-known ports, and tracking any analyzers specifically * scheduled for individual connections. */ class Manager : public plugin::ComponentManager { public: /** * Constructor. */ Manager(); /** * Destructor. */ ~Manager(); /** * Second-stage initialization of the manager. This is called late * during Zeek's initialization after any scripts are processed. */ void InitPostScript(); /** * Finished the manager's operations. */ void Done(); /** * Dumps out the state of all registered analyzers to the \c analyzer * debug stream. Should be called only after any \c zeek_init events * have executed to ensure that any of their changes are applied. */ void DumpDebug(); // Called after zeek_init() events. /** * Enables an analyzer type. Only enabled analyzers will be * instantiated for new connections. * * @param tag The analyzer's tag. * * @return True if successful. */ bool EnableAnalyzer(const zeek::Tag& tag); /** * Enables an analyzer type. Only enabled analyzers will be * instantiated for new connections. * * @param tag The analyzer's tag as an enum of script type \c * Tag. * * @return True if successful. */ bool EnableAnalyzer(EnumVal* tag); /** * Enables an analyzer type. Disabled analyzers will not be * instantiated for new connections. * * @param tag The analyzer's tag. * * @return True if successful. */ bool DisableAnalyzer(const zeek::Tag& tag); /** * Disables an analyzer type. Disabled analyzers will not be * instantiated for new connections. * * @param tag The analyzer's tag as an enum of script type \c * Tag. * * @return True if successful. */ bool DisableAnalyzer(EnumVal* tag); /** * Disables all currently registered analyzers. */ void DisableAllAnalyzers(); /** * Returns the tag associated with an analyzer name, or the tag * associated with an error if no such analyzer exists. * * @param name The canonical analyzer name to check. */ zeek::Tag GetAnalyzerTag(const char* name); /** * Returns true if an analyzer is enabled. * * @param tag The analyzer's tag. */ bool IsEnabled(const zeek::Tag& tag); /** * Returns true if an analyzer is enabled. * * @param tag The analyzer's tag as an enum of script type \c * Tag. */ bool IsEnabled(EnumVal* tag); /** * 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 as an enum of script type \c * Tag. * * @param port The well-known port. * * @return True if successful. */ bool RegisterAnalyzerForPort(EnumVal* tag, PortVal* port); /** * 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 proto The port's protocol. * * @param port The port's number. * * @return True if successful. */ bool RegisterAnalyzerForPort(const zeek::Tag& tag, TransportProto proto, uint32_t port); /** * Unregisters a well-known port for an analyzers. * * @param tag The analyzer's tag as an enum of script type \c * Tag. * * @param port The well-known port. * * @return True if successful (incl. when the port wasn't actually * registered for the analyzer). * */ bool UnregisterAnalyzerForPort(EnumVal* tag, PortVal* port); /** * Unregisters a well-known port for an analyzers. * * @param tag The analyzer's tag. * * @param proto The port's protocol. * * @param port The port's number. * * @param tag The analyzer's tag as an enum of script type \c * Tag. */ bool UnregisterAnalyzerForPort(const zeek::Tag& tag, TransportProto proto, uint32_t port); /** * Instantiates a new analyzer instance for a connection. * * @param tag The analyzer's tag. * * @param conn The connection the analyzer is to be associated with. * * @return The new analyzer instance. Note that the analyzer will not * have been added to the connection's analyzer tree yet. Returns * null if tag is invalid, the requested analyzer is disabled, or the * analyzer can't be instantiated. */ Analyzer* InstantiateAnalyzer(const zeek::Tag& tag, Connection* c); /** * Instantiates a new analyzer instance for a connection. * * @param name The name of the analyzer. * * @param conn The connection the analyzer is to be associated with. * * @return The new analyzer instance. Note that the analyzer will not * have been added to the connection's analyzer tree yet. Returns * null if the name is not known or if the requested analyzer that is * disabled. */ Analyzer* InstantiateAnalyzer(const char* name, Connection* c); /** * Schedules a particular analyzer for an upcoming connection. Once * the connection is seen, BuildInitAnalyzerTree() will add the * specified analyzer to its tree. * * @param orig The connection's anticipated originator address. * 0.0.0.0 can be used as a wildcard matching any originator. * * @param resp The connection's anticipated responder address (no * wildcard). * * @param resp_p The connection's anticipated responder port. * * @param proto The connection's anticipated transport protocol. * * @param analyzer The analyzer to use once the connection is seen. * * @param timeout An interval after which to timeout the request to * schedule this analyzer. Must be non-zero. */ void ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, uint16_t resp_p, TransportProto proto, const zeek::Tag& analyzer, double timeout); /** * Schedules a particular analyzer for an upcoming connection. Once * the connection is seen, BuildInitAnalyzerTree() will add the * specified analyzer to its tree. * * @param orig The connection's anticipated originator address. 0 can * be used as a wildcard matching any originator. * * @param resp The connection's anticipated responder address (no * wildcard). * * @param resp_p The connection's anticipated responder port. * * @param proto The connection's anticipated transport protocol. * * @param analyzer The name of the analyzer to use once the * connection is seen. * * @param timeout An interval after which to timeout the request to * schedule this analyzer. Must be non-zero. */ void ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, uint16_t resp_p, TransportProto proto, const char* analyzer, double timeout); /** * Searched for analyzers scheduled to be attached to a given connection * and then attaches them. * * @param conn The connection to which scheduled analyzers are attached. * * @param init True if the newly added analyzers should be * immediately initialized. * * @param root If given, the scheduled analyzers will become children * of this; if not given the connection's root analyzer is used * instead. * * @return True if at least one scheduled analyzer was found. */ bool ApplyScheduledAnalyzers(Connection* conn, bool init_and_event = true, packet_analysis::IP::SessionAdapter* parent = nullptr); /** * Schedules a particular analyzer for an upcoming connection. Once * the connection is seen, BuildInitAnalyzerTree() will add the * specified analyzer to its tree. * * @param orig The connection's anticipated originator address. 0 can * be used as a wildcard matching any originator. * * @param resp The connection's anticipated responder address (no * wildcard). * * @param resp_p The connection's anticipated responder port. * * @param analyzer The analyzer to use once the connection is seen as * an enum value of script-type \c Tag. * * @param timeout An interval after which to timeout the request to * schedule this analyzer. Must be non-zero. */ void ScheduleAnalyzer(const IPAddr& orig, const IPAddr& resp, PortVal* resp_p, Val* analyzer, double timeout); /** * @return the UDP port numbers to be associated with VXLAN traffic. */ const std::vector& GetVxlanPorts() const { return vxlan_ports; } private: // Internal version that must be used only once InitPostScript has completed. bool RegisterAnalyzerForPort(const std::tuple& p); friend class packet_analysis::IP::IPBasedAnalyzer; using tag_set = std::set; tag_set GetScheduled(const Connection* conn); void ExpireScheduledAnalyzers(); //// Data structures to track analyzed scheduled for future connections. // The index for a scheduled connection. struct ConnIndex { IPAddr orig; IPAddr resp; uint16_t resp_p; uint16_t proto; ConnIndex(const IPAddr& _orig, const IPAddr& _resp, uint16_t _resp_p, uint16_t _proto); ConnIndex(); bool operator<(const ConnIndex& other) const; }; // Information associated with a scheduled connection. struct ScheduledAnalyzer { ConnIndex conn; zeek::Tag analyzer; double timeout; struct Comparator { bool operator()(ScheduledAnalyzer* a, ScheduledAnalyzer* b) { return a->timeout > b->timeout; } }; }; using protocol_analyzers = std::set>; using conns_map = std::multimap; using conns_queue = std::priority_queue, ScheduledAnalyzer::Comparator>; bool initialized = false; protocol_analyzers pending_analyzers_for_ports; conns_map conns; conns_queue conns_by_timeout; std::vector vxlan_ports; }; } // namespace analyzer extern analyzer::Manager* analyzer_mgr; } // namespace zeek // Macros for analyzer debug logging which include the connection id into the // message. #ifdef DEBUG #define DBG_ANALYZER(conn, txt) \ DBG_LOG(zeek::DBG_ANALYZER, "%s " txt, \ fmt_conn_id(conn->OrigAddr(), ntohs(conn->OrigPort()), conn->RespAddr(), \ ntohs(conn->RespPort()))); #define DBG_ANALYZER_ARGS(conn, fmt, ...) \ DBG_LOG(zeek::DBG_ANALYZER, "%s " fmt, \ fmt_conn_id(conn->OrigAddr(), ntohs(conn->OrigPort()), conn->RespAddr(), \ ntohs(conn->RespPort())), \ ##__VA_ARGS__); #else #define DBG_ANALYZER(conn, txt) #define DBG_ANALYZER_ARGS(conn, fmt, ...) #endif