From 039f7b3e5f828588c14916dae426862e25a9d43c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 30 Jan 2014 11:45:30 +0100 Subject: [PATCH] tls json: turn into packet logger Like log-tls, turn the json tls logger into a packet logger as the protocol parser is not tx aware. Make it a child of eve-log as well. --- src/output-json.c | 12 --- src/output-tlslog.c | 198 ++++++++++++++++++++++++++++++++++------ src/output-tlslog.h | 1 + src/suricata.c | 3 + src/tm-threads-common.h | 1 + 5 files changed, 174 insertions(+), 41 deletions(-) diff --git a/src/output-json.c b/src/output-json.c index 71ec1cb2d6..5a88a7c924 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -361,10 +361,6 @@ TmEcode OutputJson (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pack OutputFileLog(tv, p, data); } - if (output_flags & OUTPUT_TLS) { - OutputTlsLog(tv, p, data); - } - return TM_ECODE_OK; } @@ -538,14 +534,6 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) output_flags |= OUTPUT_FILES; continue; } - if (strcmp(output->val, "tls") == 0) { - SCLogDebug("Enabling TLS output"); - ConfNode *child = ConfNodeLookupChild(output, "tls"); - json_ctx->tls_ctx = OutputTlsLogInit(child); - AppLayerParserRegisterLogger(IPPROTO_TCP,ALPROTO_TLS); - output_flags |= OUTPUT_TLS; - continue; - } } } } diff --git a/src/output-tlslog.c b/src/output-tlslog.c index 4a67b67424..0fe95fb162 100644 --- a/src/output-tlslog.c +++ b/src/output-tlslog.c @@ -61,9 +61,16 @@ SC_ATOMIC_DECLARE(unsigned int, cert_id); #define LOG_TLS_EXTENDED (1 << 0) typedef struct OutputTlsCtx_ { + LogFileCtx *file_ctx; uint32_t flags; /** Store mode */ } OutputTlsCtx; + +typedef struct JsonTlsLogThread_ { + OutputTlsCtx *tlslog_ctx; + MemBuffer *buffer; +} JsonTlsLogThread; + #define SSL_VERSION_LENGTH 13 static void LogTlsLogExtendedJSON(json_t *tjs, SSLState * state) @@ -100,20 +107,15 @@ static void LogTlsLogExtendedJSON(json_t *tjs, SSLState * state) break; } json_object_set_new(tjs, "version", json_string(ssl_version)); - } - -static TmEcode LogTlsLogIPWrapperJSON(ThreadVars *tv, Packet *p, void *data) -{ - SCEnter(); - AlertJsonThread *aft = (AlertJsonThread *)data; +static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p) { + JsonTlsLogThread *aft = (JsonTlsLogThread *)thread_data; MemBuffer *buffer = (MemBuffer *)aft->buffer; - OutputTlsCtx *tls_ctx = aft->tls_ctx->data; + OutputTlsCtx *tls_ctx = aft->tlslog_ctx; - /* no flow, no tls state */ - if (p->flow == NULL) { - SCReturnInt(TM_ECODE_OK); + if (unlikely(p->flow == NULL)) { + return 0; } /* check if we have TLS state or not */ @@ -122,19 +124,15 @@ static TmEcode LogTlsLogIPWrapperJSON(ThreadVars *tv, Packet *p, void *data) if (proto != ALPROTO_TLS) goto end; - SSLState *ssl_state = (SSLState *) FlowGetAppState(p->flow); - if (ssl_state == NULL) { - SCLogDebug("no tls state, so no request logging"); + SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); + if (unlikely(ssl_state == NULL)) { goto end; } if (ssl_state->server_connp.cert0_issuerdn == NULL || ssl_state->server_connp.cert0_subject == NULL) goto end; - if (AppLayerParserGetTransactionLogId(p->flow->alparser) != 0) - goto end; - - json_t *js = CreateJSONHeader(p, 0); + json_t *js = CreateJSONHeader((Packet *)p, 0);//TODO if (unlikely(js == NULL)) goto end; @@ -161,36 +159,75 @@ static TmEcode LogTlsLogIPWrapperJSON(ThreadVars *tv, Packet *p, void *data) json_object_set_new(js, "tls", tjs); - OutputJSON(js, aft, &aft->tls_cnt); + OutputJSONBuffer(js, tls_ctx->file_ctx, buffer); json_object_clear(js); json_decref(js); + /* we only log the state once */ + ssl_state->flags |= SSL_AL_FLAG_STATE_LOGGED; end: FLOWLOCK_UNLOCK(p->flow); - SCReturnInt(TM_ECODE_OK); - + return 0; } -TmEcode OutputTlsLog(ThreadVars *tv, Packet *p, void *data) +#define OUTPUT_BUFFER_SIZE 65535 +static TmEcode JsonTlsLogThreadInit(ThreadVars *t, void *initdata, void **data) { - SCEnter(); + JsonTlsLogThread *aft = SCMalloc(sizeof(JsonTlsLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + memset(aft, 0, sizeof(JsonTlsLogThread)); + + if(initdata == NULL) + { + SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCFree(aft); + return TM_ECODE_FAILED; + } - /* no flow, no htp state */ - if (p->flow == NULL) { - SCReturnInt(TM_ECODE_OK); + /* Use the Ouptut Context (file pointer and mutex) */ + aft->tlslog_ctx = ((OutputCtx *)initdata)->data; + + aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (aft->buffer == NULL) { + SCFree(aft); + return TM_ECODE_FAILED; } - if (!(PKT_IS_TCP(p))) { - SCReturnInt(TM_ECODE_OK); + *data = (void *)aft; + return TM_ECODE_OK; +} + +static TmEcode JsonTlsLogThreadDeinit(ThreadVars *t, void *data) +{ + JsonTlsLogThread *aft = (JsonTlsLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; } - LogTlsLogIPWrapperJSON(tv, p, data); + MemBufferFree(aft->buffer); + /* clear memory */ + memset(aft, 0, sizeof(JsonTlsLogThread)); - SCReturnInt(TM_ECODE_OK); + SCFree(aft); + return TM_ECODE_OK; } + +#define DEFAULT_LOG_FILENAME "tls.json" OutputCtx *OutputTlsLogInit(ConfNode *conf) { + LogFileCtx *file_ctx = LogFileNewCtx(); + if(file_ctx == NULL) { + SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + return NULL; + } + + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + LogFileFreeCtx(file_ctx); + return NULL; + } + OutputTlsCtx *tls_ctx = SCMalloc(sizeof(OutputTlsCtx)); if (unlikely(tls_ctx == NULL)) return NULL; @@ -199,6 +236,7 @@ OutputCtx *OutputTlsLogInit(ConfNode *conf) if (unlikely(output_ctx == NULL)) return NULL; + tls_ctx->file_ctx = file_ctx; tls_ctx->flags = LOG_TLS_DEFAULT; if (conf) { @@ -215,4 +253,106 @@ OutputCtx *OutputTlsLogInit(ConfNode *conf) return output_ctx; } + +OutputCtx *OutputTlsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AlertJsonThread *ajt = parent_ctx->data; + + OutputTlsCtx *tls_ctx = SCMalloc(sizeof(OutputTlsCtx)); + if (unlikely(tls_ctx == NULL)) + return NULL; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) + return NULL; + + tls_ctx->file_ctx = ajt->file_ctx; + tls_ctx->flags = LOG_TLS_DEFAULT; + + if (conf) { + const char *extended = ConfNodeLookupChildValue(conf, "extended"); + + if (extended != NULL) { + if (ConfValIsTrue(extended)) { + tls_ctx->flags = LOG_TLS_EXTENDED; + } + } + } + output_ctx->data = tls_ctx; + output_ctx->DeInit = NULL; + + return output_ctx; +} + +/** \internal + * \brief Condition function for TLS logger + * \retval bool true or false -- log now? + */ +static int JsonTlsCondition(ThreadVars *tv, const Packet *p) { + if (p->flow == NULL) { + return FALSE; + } + + if (!(PKT_IS_TCP(p))) { + return FALSE; + } + + FLOWLOCK_RDLOCK(p->flow); + uint16_t proto = FlowGetAppProtocol(p->flow); + if (proto != ALPROTO_TLS) + goto dontlog; + + SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); + if (ssl_state == NULL) { + SCLogDebug("no tls state, so no request logging"); + goto dontlog; + } + + /* we only log the state once */ + if (ssl_state->flags & SSL_AL_FLAG_STATE_LOGGED) + goto dontlog; + + if (ssl_state->server_connp.cert0_issuerdn == NULL || + ssl_state->server_connp.cert0_subject == NULL) + goto dontlog; + + /* todo: logic to log once */ + + FLOWLOCK_UNLOCK(p->flow); + return TRUE; +dontlog: + FLOWLOCK_UNLOCK(p->flow); + return FALSE; +} + +void TmModuleJsonTlsLogRegister (void) { + tmm_modules[TMM_JSONTLSLOG].name = "JsonTlsLog"; + tmm_modules[TMM_JSONTLSLOG].ThreadInit = JsonTlsLogThreadInit; + tmm_modules[TMM_JSONTLSLOG].ThreadDeinit = JsonTlsLogThreadDeinit; + tmm_modules[TMM_JSONTLSLOG].RegisterTests = NULL; + tmm_modules[TMM_JSONTLSLOG].cap_flags = 0; + + /* register as separate module */ + OutputRegisterPacketModule("JsonTlsLog", "tls-json-log", OutputTlsLogInit, + JsonTlsLogger, JsonTlsCondition); + + /* also register as child of eve-log */ + OutputRegisterPacketSubModule("eve-log", "JsonTlsLog", "eve-log.tls", OutputTlsLogInitSub, + JsonTlsLogger, JsonTlsCondition); +} + +#else + +static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) +{ + SCLogInfo("Can't init JSON output - JSON support was disabled during build."); + return TM_ECODE_FAILED; +} + +void TmModuleJsonTlsLogRegister (void) +{ + tmm_modules[TMM_JSONTLSLOG].name = "JsonTlsLog"; + tmm_modules[TMM_JSONTLSLOG].ThreadInit = OutputJsonThreadInit; +} + #endif diff --git a/src/output-tlslog.h b/src/output-tlslog.h index 78007cefc5..71835e78bd 100644 --- a/src/output-tlslog.h +++ b/src/output-tlslog.h @@ -26,5 +26,6 @@ TmEcode OutputTlsLog (ThreadVars *tv, Packet *p, void *data); OutputCtx *OutputTlsLogInit(ConfNode *); +void TmModuleJsonTlsLogRegister (void); #endif /* __OUTPUT_TLSLOG_H__ */ diff --git a/src/suricata.c b/src/suricata.c index 3a3576fb03..1a20728dc2 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -87,6 +87,7 @@ #include "log-dnslog.h" #include "output-dnslog.h" #include "log-tlslog.h" +#include "output-tlslog.h" #include "log-pcap.h" #include "log-file.h" #include "log-filestore.h" @@ -803,7 +804,9 @@ void RegisterAllModules() /* http log */ TmModuleLogHttpLogRegister(); TmModuleJsonHttpLogRegister(); + /* tls log */ TmModuleLogTlsLogRegister(); + TmModuleJsonTlsLogRegister(); /* pcap log */ TmModulePcapLogRegister(); /* file log */ diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index e03d70f7ac..09b8e6b25f 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -88,6 +88,7 @@ typedef enum { TMM_JSONDROPLOG, TMM_JSONHTTPLOG, TMM_JSONDNSLOG, + TMM_JSONTLSLOG, TMM_SIZE, } TmmId;