/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha */ #ifndef __UTIL_DEBUG_H__ #define __UTIL_DEBUG_H__ #include "suricata-common.h" #include "threads.h" #include "util-error.h" #include "util-debug-filters.h" /** * \brief ENV vars that can be used to set the properties for the logging module */ #define SC_LOG_ENV_LOG_LEVEL "SC_LOG_LEVEL" #define SC_LOG_ENV_LOG_OP_IFACE "SC_LOG_OP_IFACE" #define SC_LOG_ENV_LOG_FILE "SC_LOG_FILE" #define SC_LOG_ENV_LOG_FACILITY "SC_LOG_FACILITY" #define SC_LOG_ENV_LOG_FORMAT "SC_LOG_FORMAT" #define SC_LOG_ENV_LOG_OP_FILTER "SC_LOG_OP_FILTER" /** * \brief The various log levels * NOTE: when adding new level, don't forget to update SCLogMapLogLevelToSyslogLevel() * or it may result in logging to syslog with LOG_EMERG priority. */ typedef enum { SC_LOG_NOTSET = -1, SC_LOG_NONE = 0, SC_LOG_ERROR, SC_LOG_WARNING, SC_LOG_NOTICE, SC_LOG_INFO, SC_LOG_PERF, SC_LOG_CONFIG, SC_LOG_DEBUG, SC_LOG_LEVEL_MAX, } SCLogLevel; /** * \brief The various output interfaces supported */ typedef enum { SC_LOG_OP_IFACE_CONSOLE, SC_LOG_OP_IFACE_FILE, SC_LOG_OP_IFACE_SYSLOG, SC_LOG_OP_IFACE_MAX, } SCLogOPIface; typedef enum { SC_LOG_OP_TYPE_REGULAR = 0, SC_LOG_OP_TYPE_JSON, } SCLogOPType; /* The default log_format, if it is not supplied by the user */ #define SC_LOG_DEF_FILE_FORMAT "[%i - %m] %z %d: %S: %M" #define SC_LOG_DEF_LOG_FORMAT_REL_NOTICE "%D: %S: %M" #define SC_LOG_DEF_LOG_FORMAT_REL_INFO "%d: %S: %M" #define SC_LOG_DEF_LOG_FORMAT_REL_CONFIG "[%i] %d: %S: %M" #define SC_LOG_DEF_LOG_FORMAT_DEBUG "%d: %S: %M [%n:%f:%l]" /* The maximum length of the log message */ #define SC_LOG_MAX_LOG_MSG_LEN 2048 /* The maximum length of the log format */ #define SC_LOG_MAX_LOG_FORMAT_LEN 128 /* The default log level, if it is not supplied by the user */ #define SC_LOG_DEF_LOG_LEVEL SC_LOG_INFO /* The default output interface to be used */ #define SC_LOG_DEF_LOG_OP_IFACE SC_LOG_OP_IFACE_CONSOLE /* The default log file to be used */ #define SC_LOG_DEF_LOG_FILE "suricata.log" /* The default syslog facility to be used */ #define SC_LOG_DEF_SYSLOG_FACILITY_STR "local0" #define SC_LOG_DEF_SYSLOG_FACILITY LOG_LOCAL0 /** * \brief Structure to be used when log_level override support would be provided * by the logging module */ typedef struct SCLogOPBuffer_ { char msg[SC_LOG_MAX_LOG_MSG_LEN]; char *temp; const char *log_format; } SCLogOPBuffer; /** * \brief The output interface context for the logging module */ typedef struct SCLogOPIfaceCtx_ { SCLogOPIface iface; int16_t use_color; SCLogOPType type; /* the output file to be used if the interface is SC_LOG_IFACE_FILE */ const char *file; /* the output file descriptor for the above file */ FILE * file_d; /* registered to be set on a file rotation signal */ int rotation_flag; /* the facility code if the interface is SC_LOG_IFACE_SYSLOG */ int facility; /* override for the global_log_level */ SCLogLevel log_level; /* override for the global_log_format(currently not used) */ const char *log_format; /* Mutex used for locking around rotate/write to a file. */ SCMutex fp_mutex; struct SCLogOPIfaceCtx_ *next; } SCLogOPIfaceCtx; /** * \brief Structure containing init data, that would be passed to * SCInitDebugModule() */ typedef struct SCLogInitData_ { /* startup message */ const char *startup_message; /* the log level */ SCLogLevel global_log_level; /* the log format */ const char *global_log_format; /* output filter */ const char *op_filter; /* list of output interfaces to be used */ SCLogOPIfaceCtx *op_ifaces; /* no of op ifaces */ uint8_t op_ifaces_cnt; } SCLogInitData; /** * \brief Holds the config state used by the logging api */ typedef struct SCLogConfig_ { char *startup_message; SCLogLevel log_level; char *log_format; char *op_filter; /* compiled pcre filter expression */ pcre2_code *op_filter_regex; pcre2_match_data *op_filter_regex_match; /* op ifaces used */ SCLogOPIfaceCtx *op_ifaces; /* no of op ifaces */ uint8_t op_ifaces_cnt; } SCLogConfig; /* The different log format specifiers supported by the API */ #define SC_LOG_FMT_TIME 'z' /* Timestamp in RFC3339 like format */ #define SC_LOG_FMT_TIME_LEGACY 't' /* Timestamp in legacy format */ #define SC_LOG_FMT_PID 'p' /* PID */ #define SC_LOG_FMT_TID 'i' /* Thread ID */ #define SC_LOG_FMT_TM 'm' /* Thread module name */ #define SC_LOG_FMT_LOG_LEVEL 'd' /* Log level */ #define SC_LOG_FMT_LOG_SLEVEL 'D' /* Log level */ #define SC_LOG_FMT_FILE_NAME 'f' /* File name */ #define SC_LOG_FMT_LINE 'l' /* Line number */ #define SC_LOG_FMT_FUNCTION 'n' /* Function */ #define SC_LOG_FMT_SUBSYSTEM 'S' /* Subsystem name */ #define SC_LOG_FMT_THREAD_NAME 'T' /* thread name */ #define SC_LOG_FMT_MESSAGE 'M' /* log message body */ /* The log format prefix for the format specifiers */ #define SC_LOG_FMT_PREFIX '%' /* Module and thread tagging */ /* The module name, usually the containing source-module name */ static const char *_sc_module __attribute__((unused)) = __SCFILENAME__; extern SCLogLevel sc_log_global_log_level; extern int sc_log_module_initialized; extern int sc_log_module_cleaned; void SCLog(int x, const char *file, const char *func, const int line, const char *module, const char *fmt, ...) ATTR_FMT_PRINTF(6, 7); void SCLogErr(int x, const char *file, const char *func, const int line, const char *module, const char *fmt, ...) ATTR_FMT_PRINTF(6, 7); /** * \brief Macro used to log INFORMATIONAL messages. * * \retval ... Takes as argument(s), a printf style format message */ #define SCLogInfo(...) SCLog(SC_LOG_INFO, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) #define SCLogInfoRaw(file, func, line, ...) \ SCLog(SC_LOG_INFO, (file), (func), (line), _sc_module, __VA_ARGS__) #define SCLogConfig(...) \ SCLog(SC_LOG_CONFIG, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) #define SCLogPerf(...) SCLog(SC_LOG_PERF, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) /** * \brief Macro used to log NOTICE messages. * * \retval ... Takes as argument(s), a printf style format message */ #define SCLogNotice(...) \ SCLog(SC_LOG_NOTICE, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) #define SCLogNoticeRaw(file, func, line, ...) \ SCLog(SC_LOG_NOTICE, (file), (func), (line), _sc_module, __VA_ARGS__) /** * \brief Macro used to log WARNING messages. * * \retval err_code Error code that has to be logged along with the * warning message * \retval ... Takes as argument(s), a printf style format message */ #define SCLogWarning(...) \ SCLogErr(SC_LOG_WARNING, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) #define SCLogWarningRaw(file, func, line, ...) \ SCLogErr(SC_LOG_WARNING, (file), (func), (line), _sc_module, __VA_ARGS__) /** * \brief Macro used to log ERROR messages. * * \retval err_code Error code that has to be logged along with the * error message * \retval ... Takes as argument(s), a printf style format message */ #define SCLogError(...) \ SCLogErr(SC_LOG_ERROR, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) #define SCLogErrorRaw(file, func, line, ...) \ SCLogErr(SC_LOG_ERROR, (file), (func), (line), _sc_module, __VA_ARGS__) /* Avoid the overhead of using the debugging subsystem, in production mode */ #ifndef DEBUG #define SCLogDebug(...) do { } while (0) #define SCEnter(...) #define SCReturn return #define SCReturnInt(x) return x #define SCReturnUInt(x) return x #define SCReturnDbl(x) return x #define SCReturnChar(x) return x #define SCReturnCharPtr(x) return x #define SCReturnCT(x, type) return x #define SCReturnPtr(x, type) return x #define SCReturnBool(x) return x #define SCReturnStruct(x) return x /* Please use it only for debugging purposes */ #else /** * \brief Macro used to log DEBUG messages. Comes under the debugging subsystem, * and hence will be enabled only in the presence of the DEBUG macro. * * \retval ... Takes as argument(s), a printf style format message */ #define SCLogDebug(...) \ SCLog(SC_LOG_DEBUG, __FILE__, __FUNCTION__, __LINE__, _sc_module, __VA_ARGS__) /** * \brief Macro used to log debug messages on function entry. Comes under the * debugging subsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_entry logs, it also * processes the FD filters, if any FD filters are registered. * * \retval f An argument can be supplied, although it is not used */ #define SCEnter(f) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG &&\ SCLogCheckFDFilterEntry(__FUNCTION__)) \ { \ SCLogDebug("Entering ... >>"); \ } \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging subsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that don't return * a value. */ #define SCReturn do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning ... <<" ); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return; \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging subsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that returns an * integer value. * * \retval x Variable of type 'integer' that has to be returned */ #define SCReturnInt(x) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning: %"PRIdMAX" ... <<", (intmax_t)x); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging subsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that returns an * unsigned integer value. * * \retval x Variable of type 'unsigned integer' that has to be returned */ #define SCReturnUInt(x) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning: %"PRIuMAX" ... <<", (uintmax_t)x); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging subsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that returns a * float/double value. * * \retval x Variable of type 'float/double' that has to be returned */ #define SCReturnDbl(x) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning: %f ... <<", x); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging subsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that returns a var * of character type. * * \retval x Variable of type 'char' that has to be returned */ #define SCReturnChar(x) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning: %c ... <<", x); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging subsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that returns a * character string. * * \retval x Pointer to the char string that has to be returned */ #define SCReturnCharPtr(x) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ if ((x) != NULL) { \ SCLogDebug("Returning: %s ... <<", x); \ } else { \ SCLogDebug("Returning: NULL ... <<"); \ } SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging subsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that returns a var * of custom type * * \retval x Variable instance of a custom type that has to be returned * \retval type Pointer to a character string holding the name of the custom * type(the argument x) that has to be returned */ #define SCReturnCT(x, type) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning var of " \ "type %s ... <<", type); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging subsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that returns a * pointer to a custom type * * \retval x Pointer to a variable instance of a custom type that has to be * returned * \retval type Pointer to a character string holding the name of the custom * type(the argument x) that has to be returned */ #define SCReturnPtr(x, type) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning pointer %p of " \ "type %s ... <<", x, type); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) /** * \brief Macro used to log debug messages on function exit. Comes under the * debugging subsystem, and hence will be enabled only in the presence * of the DEBUG macro. Apart from logging function_exit logs, it also * processes the FD filters, if any FD filters are registered. This * function_exit macro should be used for functions that returns a * boolean value. * * \retval x Variable of type 'bool' that has to be returned */ #define SCReturnBool(x) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning: %s ... <<", x ? "true" : "false"); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) #define SCReturnStruct(x) do { \ if (sc_log_global_log_level >= SC_LOG_DEBUG) { \ SCLogDebug("Returning: ... <<"); \ SCLogCheckFDFilterExit(__FUNCTION__); \ } \ return x; \ } while(0) #endif /* DEBUG */ #define FatalError(...) \ do { \ SCLogError(__VA_ARGS__); \ exit(EXIT_FAILURE); \ } while (0) /** \brief Fatal error IF we're starting up, and configured to consider * errors to be fatal errors */ #if !defined(__clang_analyzer__) #define FatalErrorOnInit(...) \ do { \ SC_ATOMIC_EXTERN(unsigned int, engine_stage); \ int init_errors_fatal = 0; \ (void)ConfGetBool("engine.init-failure-fatal", &init_errors_fatal); \ if (init_errors_fatal && (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT)) { \ SCLogError(__VA_ARGS__); \ exit(EXIT_FAILURE); \ } \ SCLogWarning(__VA_ARGS__); \ } while (0) /* make it simpler for scan-build */ #else #define FatalErrorOnInit(...) FatalError(__VA_ARGS__) #endif #define BOOL2STR(b) (b) ? "true" : "false" SCLogInitData *SCLogAllocLogInitData(void); void SCLogAppendOPIfaceCtx(SCLogOPIfaceCtx *, SCLogInitData *); void SCLogInitLogModule(SCLogInitData *); void SCLogDeInitLogModule(void); SCError SCLogMessage(const SCLogLevel, const char *, const unsigned int, const char *, const char *, const char *message); SCLogOPBuffer *SCLogAllocLogOPBuffer(void); int SCLogDebugEnabled(void); void SCLogRegisterTests(void); void SCLogLoadConfig(int daemon, int verbose, uint32_t userid, uint32_t groupid); SCLogLevel SCLogGetLogLevel(void); #endif /* __UTIL_DEBUG_H__ */