diff --git a/src/output-tx.c b/src/output-tx.c index 582477c16408..06c8c98c7357 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -61,7 +61,7 @@ typedef struct OutputTxLogger_ { void (*ThreadExitPrintStats)(ThreadVars *, void *); } OutputTxLogger; -static OutputTxLogger *list[ALPROTO_MAX] = { NULL }; +static OutputTxLogger **list = NULL; int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, TxLogger LogFunc, @@ -71,6 +71,14 @@ int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, ThreadDeinitFunc ThreadDeinit, void (*ThreadExitPrintStats)(ThreadVars *, void *)) { + if (list == NULL) { + list = SCCalloc(ALPROTO_MAX, sizeof(OutputTxLogger *)); + if (unlikely(list == NULL)) { + SCLogError("Failed to allocate OutputTx list"); + return -1; + } + } + if (alproto != ALPROTO_UNKNOWN && !(AppLayerParserIsEnabled(alproto))) { SCLogDebug( "%s logger not enabled: protocol %s is disabled", name, AppProtoToString(alproto)); @@ -666,12 +674,21 @@ static uint32_t OutputTxLoggerGetActiveCount(void) void OutputTxLoggerRegister (void) { + BUG_ON(list); + list = SCCalloc(ALPROTO_MAX, sizeof(OutputTxLogger *)); + if (unlikely(list == NULL)) { + FatalError("Failed to allocate OutputTx list"); + } OutputRegisterRootLogger(OutputTxLogThreadInit, OutputTxLogThreadDeinit, OutputTxLogExitPrintStats, OutputTxLog, OutputTxLoggerGetActiveCount); } void OutputTxShutdown(void) { + // called in different places because of unix socket mode, and engine-analysis mode + if (list == NULL) { + return; + } for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) { OutputTxLogger *logger = list[alproto]; while (logger) { @@ -681,4 +698,6 @@ void OutputTxShutdown(void) } list[alproto] = NULL; } + SCFree(list); + list = NULL; } diff --git a/src/output.c b/src/output.c index 49b2c84ebffb..24863e643511 100644 --- a/src/output.c +++ b/src/output.c @@ -669,6 +669,8 @@ OutputModule *OutputGetModuleByConfName(const char *conf_name) return NULL; } +static EveJsonSimpleAppLayerLogger *simple_json_applayer_loggers; + /** * \brief Deregister all modules. Useful for a memory clean exit. */ @@ -680,6 +682,8 @@ void OutputDeregisterAll(void) TAILQ_REMOVE(&output_modules, module, entries); SCFree(module); } + SCFree(simple_json_applayer_loggers); + simple_json_applayer_loggers = NULL; } static int drop_loggers = 0; @@ -895,11 +899,74 @@ void TmModuleLoggerRegister(void) OutputRegisterLoggers(); } +EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto) +{ + if (alproto < ALPROTO_MAX) { + return &simple_json_applayer_loggers[alproto]; + } + return NULL; +} + +static void RegisterSimpleJsonApplayerLogger( + AppProto alproto, EveJsonSimpleTxLogFunc LogTx, const char *name) +{ + simple_json_applayer_loggers[alproto].LogTx = LogTx; + if (name) { + simple_json_applayer_loggers[alproto].name = name; + } else { + simple_json_applayer_loggers[alproto].name = AppProtoToString(alproto); + } +} + /** * \brief Register all root loggers. */ void OutputRegisterRootLoggers(void) { + simple_json_applayer_loggers = SCCalloc(ALPROTO_MAX, sizeof(EveJsonSimpleAppLayerLogger)); + if (unlikely(simple_json_applayer_loggers == NULL)) { + FatalError("Failed to allocate simple_json_applayer_loggers"); + } + // ALPROTO_HTTP1 special: uses some options flags + RegisterSimpleJsonApplayerLogger(ALPROTO_FTP, EveFTPLogCommand, NULL); + // ALPROTO_SMTP special: uses state + RegisterSimpleJsonApplayerLogger(ALPROTO_TLS, JsonTlsLogJSONExtended, NULL); + // no cast here but done in rust for SSHTransaction + RegisterSimpleJsonApplayerLogger(ALPROTO_SSH, rs_ssh_log_json, NULL); + // ALPROTO_SMB special: uses state + // ALPROTO_DCERPC special: uses state + RegisterSimpleJsonApplayerLogger(ALPROTO_DNS, AlertJsonDns, NULL); + // either need a cast here or in rust for ModbusTransaction, done here + RegisterSimpleJsonApplayerLogger( + ALPROTO_MODBUS, (EveJsonSimpleTxLogFunc)rs_modbus_to_json, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_ENIP, SCEnipLoggerLog, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_DNP3, AlertJsonDnp3, NULL); + // ALPROTO_NFS special: uses state + // underscore instead of dash for ftp_data + RegisterSimpleJsonApplayerLogger(ALPROTO_FTPDATA, EveFTPDataAddMetadata, "ftp_data"); + RegisterSimpleJsonApplayerLogger( + ALPROTO_TFTP, (EveJsonSimpleTxLogFunc)rs_tftp_log_json_request, NULL); + // ALPROTO_IKE special: uses state + RegisterSimpleJsonApplayerLogger( + ALPROTO_KRB5, (EveJsonSimpleTxLogFunc)rs_krb5_log_json_response, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_QUIC, rs_quic_to_json, NULL); + // ALPROTO_DHCP TODO missing + RegisterSimpleJsonApplayerLogger( + ALPROTO_SNMP, (EveJsonSimpleTxLogFunc)rs_snmp_log_json_response, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_SIP, (EveJsonSimpleTxLogFunc)rs_sip_log_json, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_RFB, rs_rfb_logger_log, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_MQTT, JsonMQTTAddMetadata, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_PGSQL, JsonPgsqlAddMetadata, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_WEBSOCKET, rs_websocket_logger_log, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_LDAP, rs_ldap_logger_log, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_TEMPLATE, rs_template_logger_log, NULL); + RegisterSimpleJsonApplayerLogger(ALPROTO_RDP, (EveJsonSimpleTxLogFunc)rs_rdp_to_json, NULL); + // special case : http2 is logged in http object + RegisterSimpleJsonApplayerLogger(ALPROTO_HTTP2, rs_http2_log_json, "http"); + // underscore instead of dash for bittorrent_dht + RegisterSimpleJsonApplayerLogger( + ALPROTO_BITTORRENT_DHT, rs_bittorrent_dht_logger_log, "bittorrent_dht"); + OutputPacketLoggerRegister(); OutputFiledataLoggerRegister(); OutputFileLoggerRegister(); @@ -916,24 +983,7 @@ static int JsonGenericLogger(ThreadVars *tv, void *thread_data, const Packet *p, return TM_ECODE_FAILED; } - const char *name; - switch (al->proto) { - case ALPROTO_HTTP2: - // special case - name = "http"; - break; - case ALPROTO_FTPDATA: - // underscore instead of dash - name = "ftp_data"; - break; - case ALPROTO_BITTORRENT_DHT: - // underscore instead of dash - name = "bittorrent_dht"; - break; - default: - name = AppProtoToString(al->proto); - } - JsonBuilder *js = CreateEveHeader(p, dir, name, NULL, thread->ctx); + JsonBuilder *js = CreateEveHeader(p, dir, al->name, NULL, thread->ctx); if (unlikely(js == NULL)) { return TM_ECODE_FAILED; } @@ -1119,56 +1169,3 @@ void OutputRegisterLoggers(void) /* ARP JSON logger */ JsonArpLogRegister(); } - -static EveJsonSimpleAppLayerLogger simple_json_applayer_loggers[ALPROTO_MAX] = { - { ALPROTO_UNKNOWN, NULL }, - { ALPROTO_HTTP1, NULL }, // special: uses some options flags - { ALPROTO_FTP, EveFTPLogCommand }, - { ALPROTO_SMTP, NULL }, // special: uses state - { ALPROTO_TLS, JsonTlsLogJSONExtended }, - { ALPROTO_SSH, rs_ssh_log_json }, - { ALPROTO_IMAP, NULL }, // protocol detection only - { ALPROTO_JABBER, NULL }, // no parser, no logging - { ALPROTO_SMB, NULL }, // special: uses state - { ALPROTO_DCERPC, NULL }, // special: uses state - { ALPROTO_IRC, NULL }, // no parser, no logging - { ALPROTO_DNS, AlertJsonDns }, - { ALPROTO_MODBUS, (EveJsonSimpleTxLogFunc)rs_modbus_to_json }, - { ALPROTO_ENIP, SCEnipLoggerLog }, - { ALPROTO_DNP3, AlertJsonDnp3 }, - { ALPROTO_NFS, NULL }, // special: uses state - { ALPROTO_NTP, NULL }, // no logging - { ALPROTO_FTPDATA, EveFTPDataAddMetadata }, - { ALPROTO_TFTP, (EveJsonSimpleTxLogFunc)rs_tftp_log_json_request }, - { ALPROTO_IKE, NULL }, // special: uses state - { ALPROTO_KRB5, (EveJsonSimpleTxLogFunc)rs_krb5_log_json_response }, - { ALPROTO_QUIC, rs_quic_to_json }, - { ALPROTO_DHCP, NULL }, // TODO missing - { ALPROTO_SNMP, (EveJsonSimpleTxLogFunc)rs_snmp_log_json_response }, - { ALPROTO_SIP, (EveJsonSimpleTxLogFunc)rs_sip_log_json }, - { ALPROTO_RFB, rs_rfb_logger_log }, - { ALPROTO_MQTT, JsonMQTTAddMetadata }, - { ALPROTO_PGSQL, JsonPgsqlAddMetadata }, - { ALPROTO_TELNET, NULL }, // no logging - { ALPROTO_WEBSOCKET, rs_websocket_logger_log }, - { ALPROTO_LDAP, rs_ldap_logger_log }, - { ALPROTO_TEMPLATE, rs_template_logger_log }, - { ALPROTO_RDP, (EveJsonSimpleTxLogFunc)rs_rdp_to_json }, - { ALPROTO_HTTP2, rs_http2_log_json }, - { ALPROTO_BITTORRENT_DHT, rs_bittorrent_dht_logger_log }, - { ALPROTO_POP3, NULL }, // protocol detection only - { ALPROTO_HTTP, NULL }, // signature protocol, not for app-layer logging - { ALPROTO_FAILED, NULL }, -#ifdef UNITTESTS - { ALPROTO_TEST, NULL }, -#endif /* UNITESTS */ -}; - -EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto) -{ - if (alproto < ALPROTO_MAX) { - BUG_ON(simple_json_applayer_loggers[alproto].proto != alproto); - return &simple_json_applayer_loggers[alproto]; - } - return NULL; -} diff --git a/src/output.h b/src/output.h index 6c477547e66f..074d20bf5bf2 100644 --- a/src/output.h +++ b/src/output.h @@ -192,8 +192,8 @@ void OutputClearActiveLoggers(void); typedef bool (*EveJsonSimpleTxLogFunc)(void *, struct JsonBuilder *); typedef struct EveJsonSimpleAppLayerLogger { - AppProto proto; EveJsonSimpleTxLogFunc LogTx; + const char *name; } EveJsonSimpleAppLayerLogger; EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto); diff --git a/src/runmodes.c b/src/runmodes.c index 4f84149001a8..0fc8285eb4ff 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -525,7 +525,6 @@ static void RunOutputFreeList(void) static int file_logger_count = 0; static int filedata_logger_count = 0; -static LoggerId logger_bits[ALPROTO_MAX]; int RunModeOutputFiledataEnabled(void) { @@ -596,7 +595,8 @@ static void AddOutputToFreeList(OutputModule *module, OutputCtx *output_ctx) } /** \brief Turn output into thread module */ -static void SetupOutput(const char *name, OutputModule *module, OutputCtx *output_ctx) +static void SetupOutput( + const char *name, OutputModule *module, OutputCtx *output_ctx, LoggerId *logger_bits) { /* flow logger doesn't run in the packet path */ if (module->FlowLogFunc) { @@ -657,7 +657,7 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu } } -static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx) +static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx, LoggerId *logger_bits) { ConfNode *types = ConfNodeLookupChild(conf, "types"); SCLogDebug("types %p", types); @@ -710,8 +710,7 @@ static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx) } AddOutputToFreeList(sub_module, result.ctx); - SetupOutput(sub_module->name, sub_module, - result.ctx); + SetupOutput(sub_module->name, sub_module, result.ctx, logger_bits); } } @@ -724,7 +723,7 @@ static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx) } } -static void RunModeInitializeLuaOutput(ConfNode *conf, OutputCtx *parent_ctx) +static void RunModeInitializeLuaOutput(ConfNode *conf, OutputCtx *parent_ctx, LoggerId *logger_bits) { OutputModule *lua_module = OutputGetModuleByConfName("lua"); BUG_ON(lua_module == NULL); @@ -752,7 +751,7 @@ static void RunModeInitializeLuaOutput(ConfNode *conf, OutputCtx *parent_ctx) } AddOutputToFreeList(m, result.ctx); - SetupOutput(m->name, m, result.ctx); + SetupOutput(m->name, m, result.ctx, logger_bits); } } @@ -775,8 +774,8 @@ void RunModeInitializeOutputs(void) char tls_log_enabled = 0; char tls_store_present = 0; - memset(&logger_bits, 0, sizeof(logger_bits)); - + // ALPROTO_MAX is set to its final value + LoggerId logger_bits[ALPROTO_MAX] = { 0 }; TAILQ_FOREACH(output, &outputs->head, next) { output_config = ConfNodeLookupChild(output, output->val); @@ -842,7 +841,7 @@ void RunModeInitializeOutputs(void) // TODO if module == parent, find it's children if (strcmp(output->val, "eve-log") == 0) { - RunModeInitializeEveOutput(output_config, output_ctx); + RunModeInitializeEveOutput(output_config, output_ctx, logger_bits); /* add 'eve-log' to free list as it's the owner of the * main output ctx from which the sub-modules share the @@ -852,11 +851,11 @@ void RunModeInitializeOutputs(void) SCLogDebug("handle lua"); if (output_ctx == NULL) continue; - RunModeInitializeLuaOutput(output_config, output_ctx); + RunModeInitializeLuaOutput(output_config, output_ctx, logger_bits); AddOutputToFreeList(module, output_ctx); } else { AddOutputToFreeList(module, output_ctx); - SetupOutput(module->name, module, output_ctx); + SetupOutput(module->name, module, output_ctx, logger_bits); } } if (count == 0) { @@ -895,7 +894,7 @@ void RunModeInitializeOutputs(void) } AddOutputToFreeList(module, output_ctx); - SetupOutput(module->name, module, output_ctx); + SetupOutput(module->name, module, output_ctx, logger_bits); } } } diff --git a/src/suricata.c b/src/suricata.c index 13b48fe91770..a20b5f39cbcb 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -386,6 +386,7 @@ void GlobalsDestroy(void) AppLayerDeSetup(); DatasetsSave(); DatasetsDestroy(); + OutputTxShutdown(); TagDestroyCtx(); LiveDeviceListClean();