// See the file "COPYING" in the main distribution directory for copyright. #pragma once #include #include #include #include #include #include #include #include #include "zeek/ZeekList.h" #include "zeek/net_util.h" namespace zeek { class Connection; class EventHandlerPtr; class RecordVal; class StringVal; class IPAddr; class Reporter; template class IntrusivePtr; using RecordValPtr = IntrusivePtr; using StringValPtr = IntrusivePtr; namespace detail { class AssertStmt; class Expr; class Frame; class Location; } // namespace detail namespace analyzer { class Analyzer; } namespace file_analysis { class File; } // One cannot raise this exception directly, go through the // Reporter's methods instead. class ReporterException { protected: friend class Reporter; ReporterException() {} }; class InterpreterException : public ReporterException { protected: friend class Reporter; friend class detail::AssertStmt; InterpreterException() {} }; #define FMT_ATTR __attribute__((format(printf, 2, 3))) // sic! 1st is "this" I guess. class Reporter { public: using IPPair = std::pair; using ConnTuple = std::tuple; using WeirdCountMap = std::unordered_map; using WeirdFlowMap = std::map; using WeirdConnTupleMap = std::map; using WeirdSet = std::unordered_set; Reporter(bool abort_on_scripting_errors); ~Reporter(); // Initialize reporter-specific options that are defined in script-layer. void InitOptions(); // Report an informational message, nothing that needs specific // attention. void Info(const char* fmt, ...) FMT_ATTR; // Report a warning that may indicate a problem. void Warning(const char* fmt, ...) FMT_ATTR; // Report a non-fatal error. Processing proceeds normally after the error // has been reported. void Error(const char* fmt, ...) FMT_ATTR; // Returns the number of errors reported so far. int Errors() { return errors; } // Report a fatal error. Zeek will terminate after the message has been // reported. [[noreturn]] void FatalError(const char* fmt, ...) FMT_ATTR; // Report a fatal error. Zeek will terminate after the message has been // reported and always generate a core dump. [[noreturn]] void FatalErrorWithCore(const char* fmt, ...) FMT_ATTR; // Report a runtime error in evaluating a Zeek script expression. This // function will not return but raise an InterpreterException. [[noreturn]] void ExprRuntimeError(const detail::Expr* expr, const char* fmt, ...) __attribute__((format(printf, 3, 4))); // Report a runtime error in evaluating a Zeek script expression. This // function will not return but raise an InterpreterException. [[noreturn]] void RuntimeError(const detail::Location* location, const char* fmt, ...) __attribute__((format(printf, 3, 4))); // Report a rutnime warning in evaluating a Zeek script expression. void ExprRuntimeWarning(const detail::Expr* expr, const char* fmt, ...) __attribute__((format(printf, 3, 4))); // Report a runtime error in executing a compiled script. This // function will not return but raise an InterpreterException. [[noreturn]] void CPPRuntimeError(const char* fmt, ...) __attribute__((format(printf, 2, 3))); // Similar, but for warnings. This function does return. void CPPRuntimeWarning(const char* fmt, ...) __attribute__((format(printf, 2, 3))); // Report a traffic weirdness, i.e., an unexpected protocol situation // that may lead to incorrectly processing a connection. void Weird(const char* name, const char* addl = "", const char* source = ""); // Raises net_weird(). void Weird(file_analysis::File* f, const char* name, const char* addl = "", const char* source = ""); // Raises file_weird(). void Weird(Connection* conn, const char* name, const char* addl = "", const char* source = ""); // Raises conn_weird(). void Weird(RecordValPtr conn_id, StringValPtr uid, const char* name, const char* addl = "", const char* source = ""); // Raises expired_conn_weird(). void Weird(const IPAddr& orig, const IPAddr& resp, const char* name, const char* addl = "", const char* source = ""); // Raises flow_weird(). // Report a deprecation. The message should contain a version. void Deprecation(std::string_view msg, const detail::Location* loc1 = nullptr, const detail::Location* loc2 = nullptr); // Whether or not deprecations are logged when calling Deprecation() void SetIgnoreDeprecations(bool arg) { ignore_deprecations = arg; } // Syslog a message. This methods does nothing if we're running // offline from a trace. void Syslog(const char* fmt, ...) FMT_ATTR; // Report about a potential internal problem. Zeek will continue // normally. void InternalWarning(const char* fmt, ...) FMT_ATTR; // Report an internal program error. Zeek will terminate with a core // dump after the message has been reported. [[noreturn]] void InternalError(const char* fmt, ...) FMT_ATTR; // Report an analyzer error. That analyzer will be set to not process // any further input, but Zeek otherwise continues normally. void AnalyzerError(analyzer::Analyzer* a, const char* fmt, ...) __attribute__((format(printf, 3, 4))); ; // Toggle whether non-fatal messages should be reported through the // scripting layer rather on standard output. Fatal errors are always // reported via stderr. void ReportViaEvents(bool arg_via_events) { via_events = arg_via_events; } // Associates the given location with subsequent output. We create a // stack of location so that the most recent is always the one that // will be assumed to be the current one. The pointer must remain // valid until the location is popped. void PushLocation(const detail::Location* location) { locations.emplace_back(location, nullptr); } void PushLocation(const detail::Location* loc1, const detail::Location* loc2) { locations.emplace_back(loc1, loc2); } // Removes the top-most location information from stack. void PopLocation() { locations.pop_back(); } // Signals that we're entering processing an error handler event. void BeginErrorHandler() { ++in_error_handler; } // Signals that we're done processing an error handler event. void EndErrorHandler() { --in_error_handler; } /** * Reset/cleanup state tracking for a "net" weird. */ void ResetNetWeird(const std::string& name); /** * Reset/cleanup state tracking for a "flow" weird. */ void ResetFlowWeird(const IPAddr& orig, const IPAddr& resp); /** * Reset/cleanup state tracking for a "expired conn" weird. */ void ResetExpiredConnWeird(const ConnTuple& id); /** * Return the total number of weirds generated (counts weirds before * any rate-limiting occurs). */ uint64_t GetWeirdCount() const { return weird_count; } /** * Return number of weirds generated per weird type/name (counts weirds * before any rate-limiting occurs). */ const WeirdCountMap& GetWeirdsByType() const { return weird_count_by_type; } /** * Gets the weird sampling whitelist. */ const WeirdSet& GetWeirdSamplingWhitelist() const { return weird_sampling_whitelist; } /** * Sets the weird sampling whitelist. * * @param weird_sampling_whitelist New weird sampling whitelist. */ void SetWeirdSamplingWhitelist(WeirdSet weird_sampling_whitelist) { this->weird_sampling_whitelist = std::move(weird_sampling_whitelist); } /** * Gets the weird sampling global list. */ const WeirdSet& GetWeirdSamplingGlobalList() const { return weird_sampling_global_list; } /** * Sets the weird sampling global list. * * @param weird_sampling_global list New weird sampling global list. */ void SetWeirdSamplingGlobalList(WeirdSet weird_sampling_global_list) { this->weird_sampling_global_list = std::move(weird_sampling_global_list); } /** * Gets the current weird sampling threshold. * * @return weird sampling threshold. */ uint64_t GetWeirdSamplingThreshold() const { return weird_sampling_threshold; } /** * Sets the current weird sampling threshold. * * @param weird_sampling_threshold New weird sampling threshold. */ void SetWeirdSamplingThreshold(uint64_t weird_sampling_threshold) { this->weird_sampling_threshold = weird_sampling_threshold; } /** * Gets the current weird sampling rate. * * @return weird sampling rate. */ uint64_t GetWeirdSamplingRate() const { return weird_sampling_rate; } /** * Sets the weird sampling rate. * * @param weird_sampling_rate New weird sampling rate. */ void SetWeirdSamplingRate(uint64_t weird_sampling_rate) { this->weird_sampling_rate = weird_sampling_rate; } /** * Gets the current weird sampling duration. * * @return weird sampling duration. */ double GetWeirdSamplingDuration() const { return weird_sampling_duration; } /** * Sets the current weird sampling duration. Please note that * this will not delete already running timers. * * @param weird_sampling_duration New weird sampling duration. */ void SetWeirdSamplingDuration(double weird_sampling_duration) { this->weird_sampling_duration = weird_sampling_duration; } private: void DoLog(const char* prefix, EventHandlerPtr event, FILE* out, Connection* conn, ValPList* addl, bool location, bool time, const char* postfix, const char* fmt, va_list ap) __attribute__((format(printf, 10, 0))); // WeirdHelper doesn't really have to be variadic, but it calls DoLog // and that takes va_list anyway. void WeirdHelper(EventHandlerPtr event, ValPList vl, const char* fmt_name, ...) __attribute__((format(printf, 4, 5))); ; void UpdateWeirdStats(const char* name); inline bool WeirdOnSamplingWhiteList(const char* name) { return weird_sampling_whitelist.contains(name); } inline bool WeirdOnGlobalList(const char* name) { return weird_sampling_global_list.contains(name); } bool PermitNetWeird(const char* name); bool PermitFlowWeird(const char* name, const IPAddr& o, const IPAddr& r); bool PermitExpiredConnWeird(const char* name, const RecordVal& conn_id); enum class PermitWeird : uint8_t { Allow, Deny, Unknown }; PermitWeird CheckGlobalWeirdLists(const char* name); bool EmitToStderr(bool flag); int errors; int in_error_handler; bool via_events; bool syslog_open; bool info_to_stderr; bool warnings_to_stderr; bool errors_to_stderr; bool abort_on_scripting_errors = false; std::list> locations; uint64_t weird_count; WeirdCountMap weird_count_by_type; WeirdCountMap net_weird_state; WeirdFlowMap flow_weird_state; WeirdConnTupleMap expired_conn_weird_state; WeirdSet weird_sampling_whitelist; WeirdSet weird_sampling_global_list; uint64_t weird_sampling_threshold; uint64_t weird_sampling_rate; double weird_sampling_duration; bool ignore_deprecations; }; /** * Helper class pushing the frame's call location onto * the reporter's location stack, associating the caller's * location with subsequent output. * * The frame's location must remain valid until the object * is destroyed. */ class ScriptLocationScope { public: ScriptLocationScope(const zeek::detail::Frame* frame); ~ScriptLocationScope(); }; extern Reporter* reporter; } // namespace zeek