From e634fcee60d0c67394743e1f00720b7dc7217a20 Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Wed, 30 Sep 2015 10:42:26 +0200 Subject: [PATCH] lua: TLS lua output support Support TLS in lua output scripts (Feature #1568). function init (args) local needs = {} needs["protocol"] = "tls" return needs end function setup (args) filename = SCLogPath() .. "/" .. "lua_tls.log" file = assert(io.open(filename, "a")) end function log (args) ts = SCPacketTimeString() ipver, srcip, dstip, proto, sp, dp = SCFlowTuple() version, subject, issuer, fingerprint = TlsGetCertInfo(); if version == nil then return 0 end file:write(ts .. " " .. srcip .. ":" .. sp .. " -> " .. dstip .. ":" .. dp .. " TLS: " .. "Subject='" .. subject .. "' " .. "Issuerdn='" .. issuer .. "\n") file:flush() end function deinit (args) file:close(file) end --- src/app-layer-ssl.h | 2 ++ src/output-lua.c | 88 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 5c6fe5b153..2fc1a9699b 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -81,6 +81,8 @@ enum { /* flags for file storage */ #define SSL_AL_FLAG_STATE_STORED 0x40000 +#define SSL_AL_FLAG_STATE_LOGGED_LUA 0x80000 + /* config flags */ #define SSL_TLS_LOG_PEM (1 << 0) diff --git a/src/output-lua.c b/src/output-lua.c index fc5a562164..0d6e4e8add 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -40,6 +40,7 @@ #include "output.h" #include "app-layer-htp.h" #include "app-layer.h" +#include "app-layer-ssl.h" #include "app-layer-parser.h" #include "util-privs.h" #include "util-buffer.h" @@ -57,6 +58,7 @@ #include "util-lua-common.h" #include "util-lua-http.h" #include "util-lua-dns.h" +#include "util-lua-tls.h" #define MODULE_NAME "LuaLog" @@ -228,6 +230,86 @@ static int LuaPacketConditionAlerts(ThreadVars *tv, const Packet *p) return FALSE; } +/** \internal + * \brief Packet Logger for lua scripts, for tls + * + * A single call to this function will run one script for a single + * packet. If it is called, it means that the registered condition + * function has returned TRUE. + * + * The script is called once for each packet. + */ +static int LuaPacketLoggerTls(ThreadVars *tv, void *thread_data, const Packet *p) +{ + LogLuaThreadCtx *td = (LogLuaThreadCtx *)thread_data; + + char timebuf[64]; + CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); + + SCMutexLock(&td->lua_ctx->m); + + lua_getglobal(td->lua_ctx->luastate, "log"); + + LuaStateSetThreadVars(td->lua_ctx->luastate, tv); + LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p); + LuaStateSetFlow(td->lua_ctx->luastate, p->flow, /* unlocked */LUA_FLOW_NOT_LOCKED_BY_PARENT); + + int retval = lua_pcall(td->lua_ctx->luastate, 0, 0, 0); + if (retval != 0) { + SCLogInfo("failed to run script: %s", lua_tostring(td->lua_ctx->luastate, -1)); + } + + SCMutexUnlock(&td->lua_ctx->m); + FLOWLOCK_WRLOCK(p->flow); + + SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); + if (ssl_state != NULL) + ssl_state->flags |= SSL_AL_FLAG_STATE_LOGGED_LUA; + + FLOWLOCK_UNLOCK(p->flow); + SCReturnInt(0); +} + +static int LuaPacketConditionTls(ThreadVars *tv, const Packet *p) +{ + if (p->flow == NULL) { + return FALSE; + } + + if (!(PKT_IS_IPV4(p)) && !(PKT_IS_IPV6(p))) { + 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; + } + + if (ssl_state->server_connp.cert0_issuerdn == NULL || + ssl_state->server_connp.cert0_subject == NULL) + goto dontlog; + + /* We only log the state once */ + if (ssl_state->flags & SSL_AL_FLAG_STATE_LOGGED_LUA) + goto dontlog; + + FLOWLOCK_UNLOCK(p->flow); + return TRUE; +dontlog: + FLOWLOCK_UNLOCK(p->flow); + return FALSE; +} + /** \internal * \brief Packet Logger for lua scripts, for packets * @@ -517,6 +599,8 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { options->alproto = ALPROTO_HTTP; else if (strcmp(k,"protocol") == 0 && strcmp(v, "dns") == 0) options->alproto = ALPROTO_DNS; + else if (strcmp(k,"protocol") == 0 && strcmp(v, "tls") == 0) + options->alproto = ALPROTO_TLS; else if (strcmp(k, "type") == 0 && strcmp(v, "packet") == 0) options->packet = 1; else if (strcmp(k, "filter") == 0 && strcmp(v, "alerts") == 0) @@ -617,6 +701,7 @@ static lua_State *LuaScriptSetup(const char *filename) * if the tx is registered in the state at runtime though. */ LuaRegisterHttpFunctions(luastate); LuaRegisterDnsFunctions(luastate); + LuaRegisterTlsFunctions(luastate); if (lua_pcall(luastate, 0, 0, 0) != 0) { SCLogError(SC_ERR_LUA_ERROR, "couldn't run script 'setup' function: %s", lua_tostring(luastate, -1)); @@ -760,6 +845,9 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) om->TxLogFunc = LuaTxLogger; om->alproto = ALPROTO_HTTP; AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP); + } else if (opts.alproto == ALPROTO_TLS) { + om->PacketLogFunc = LuaPacketLoggerTls; + om->PacketConditionFunc = LuaPacketConditionTls; } else if (opts.alproto == ALPROTO_DNS) { om->TxLogFunc = LuaTxLogger; om->alproto = ALPROTO_DNS;