// See the file "COPYING" in the main distribution directory for copyright. /** * The central management unit for registering and instantiating analyzers. * * For each protocol that Bro 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. */ #ifndef ANALYZER_MANAGER_H #define ANALYZER_MANAGER_H #include #include "Analyzer.h" #include "Component.h" #include "Tag.h" #include "plugin/ComponentManager.h" #include "../Dict.h" #include "../net_util.h" #include "../IP.h" #include "analyzer/analyzer.bif.h" 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 analyzer::Tag. It * instantantiates 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 individidual connections. * * Note that we keep the public interface of this class free of std::* * classes. This allows to external analyzer code to potentially use a * different C++ standard library. */ class Manager : public plugin::ComponentManager { public: /** * Constructor. */ Manager(); /** * Destructor. */ ~Manager(); /** * First-stage initializion of the manager. This is called early on * during Bro's initialization, before any scripts are processed. */ void InitPreScript(); /** * Second-stage initialization of the manager. This is called late * during Bro'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 bro_init events * have executed to ensure that any of their changes are applied. */ void DumpDebug(); // Called after bro_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(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 * Analyzer::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(Tag tag); /** * Enables 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 * Analyzer::Tag. * * @return True if successful. */ bool DisableAnalyzer(EnumVal* tag); /** * Disables all currently registered analyzers. */ void DisableAllAnalyzers(); /** * Returns the tag associated with an analyer name, or the tag * associated with an error if no such analyzer exists. * * @param name The canonical analyzer name to check. */ Tag GetAnalyzerTag(const char* name); /** * Returns true if an analyzer is enabled. * * @param tag The analyzer's tag. */ bool IsEnabled(Tag tag); /** * Returns true if an analyzer is enabled. * * @param tag The analyzer's tag as an enum of script type \c * Analyzer::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 * Analyzer::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(Tag tag, TransportProto proto, uint32 port); /** * Unregisters a well-known port for an anlyzers. * * @param tag The analyzer's tag as an enum of script type \c * Analyzer::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 anlyzers. * * @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 * Analyzer::Tag. */ bool UnregisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 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(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); /** * Given the first packet of a connection, builds its initial * analyzer tree. * * @param conn The connection to add the initial set of analyzers to. * * @return False if the tree cannot be build; that's usually an * internally error. */ bool BuildInitialAnalyzerTree(Connection* conn); /** * 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 * wilcard). * * @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 resp_p, TransportProto proto, 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 The connection's anticipated responder address (no * wilcard). * * @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 resp_p, TransportProto proto, const char* 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 * wilcard). * * @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 Analyzer::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); private: typedef set tag_set; typedef map analyzer_map_by_port; tag_set* LookupPort(PortVal* val, bool add_if_not_found); tag_set* LookupPort(TransportProto proto, uint32 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; Tag analyzer_backdoor; Tag analyzer_connsize; Tag analyzer_interconn; Tag analyzer_stepping; Tag analyzer_tcpstats; //// Data structures to track analyzed scheduled for future connections. // The index for a scheduled connection. struct ConnIndex { IPAddr orig; IPAddr resp; uint16 resp_p; uint16 proto; ConnIndex(const IPAddr& _orig, const IPAddr& _resp, uint16 _resp_p, uint16 _proto); ConnIndex(); bool operator<(const ConnIndex& other) const; }; // Information associated with a scheduled connection. struct ScheduledAnalyzer { ConnIndex conn; Tag analyzer; double timeout; struct Comparator { bool operator() (ScheduledAnalyzer* a, ScheduledAnalyzer* b) { return a->timeout > b->timeout; } }; }; typedef std::multimap conns_map; typedef std::priority_queue, ScheduledAnalyzer::Comparator> conns_queue; conns_map conns; conns_queue conns_by_timeout; }; } extern analyzer::Manager* analyzer_mgr; // Macros for anayzer debug logging which include the connection id into the // message. #ifdef DEBUG # define DBG_ANALYZER(conn, txt) \ DBG_LOG(DBG_ANALYZER, "%s " txt, \ fmt_conn_id(conn->OrigAddr(), ntohs(conn->OrigPort()), \ conn->RespAddr(), ntohs(conn->RespPort()))); # define DBG_ANALYZER_ARGS(conn, fmt, args...) \ DBG_LOG(DBG_ANALYZER, "%s " fmt, \ fmt_conn_id(conn->OrigAddr(), ntohs(conn->OrigPort()), \ conn->RespAddr(), ntohs(conn->RespPort())), ##args); #else # define DBG_ANALYZER(conn, txt) # define DBG_ANALYZER_ARGS(conn, fmt, args...) #endif #endif