diff --git a/src/Makefile.am b/src/Makefile.am index 8cb82706e8..df2f98f8a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -216,6 +216,7 @@ log-tlslog.c log-tlslog.h \ output.c output.h \ output-file.c output-file.h \ output-filedata.c output-filedata.h \ +output-json-alert.c output-json-alert.h \ output-json-file.c output-json-file.h \ output-packet.c output-packet.h \ output-tx.c output-tx.h \ diff --git a/src/output-json-alert.c b/src/output-json-alert.c new file mode 100644 index 0000000000..c09d211614 --- /dev/null +++ b/src/output-json-alert.c @@ -0,0 +1,324 @@ +/* Copyright (C) 2013-2014 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 Tom DeCanio + * + * Logs alerts in JSON format. + * + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "flow.h" +#include "conf.h" + +#include "threads.h" +#include "tm-threads.h" +#include "threadvars.h" +#include "util-debug.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-reference.h" +#include "app-layer-parser.h" +#include "util-classification-config.h" +#include "util-syslog.h" + +#include "output.h" +#include "output-dnslog.h" +#include "output-droplog.h" +#include "output-httplog.h" +#include "output-tlslog.h" +#include "output-json-file.h" +#include "output-json.h" + +#include "util-byte.h" +#include "util-privs.h" +#include "util-print.h" +#include "util-proto-name.h" +#include "util-optimize.h" +#include "util-buffer.h" +#include "util-logopenfile.h" + +#define MODULE_NAME "JsonAlertLog" + +#ifdef HAVE_LIBJANSSON + +extern int engine_mode; + +typedef struct JsonAlertLogThread_ { + /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ + LogFileCtx* file_ctx; + MemBuffer *buffer; +} JsonAlertLogThread; + +/** Handle the case where no JSON support is compiled in. + * + */ +static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) +{ + MemBuffer *buffer = (MemBuffer *)aft->buffer; + int i; + char *action = "Pass"; + + if (p->alerts.cnt == 0) + return TM_ECODE_OK; + + MemBufferReset(buffer); + + json_t *js = CreateJSONHeader((Packet *)p, 0); + if (unlikely(js == NULL)) + return TM_ECODE_OK; + + for (i = 0; i < p->alerts.cnt; i++) { + const PacketAlert *pa = &p->alerts.alerts[i]; + if (unlikely(pa->s == NULL)) { + continue; + } + + if ((pa->action & ACTION_DROP) && IS_ENGINE_MODE_IPS(engine_mode)) { + action = "Drop"; + } else if (pa->action & ACTION_DROP) { + action = "wDrop"; + } + + json_t *ajs = json_object(); + if (ajs == NULL) { + json_decref(js); + return TM_ECODE_OK; + } + + json_object_set_new(ajs, "action", json_string(action)); + json_object_set_new(ajs, "gid", json_integer(pa->s->gid)); + json_object_set_new(ajs, "id", json_integer(pa->s->id)); + json_object_set_new(ajs, "rev", json_integer(pa->s->rev)); + json_object_set_new(ajs, "msg", + json_string((pa->s->msg) ? pa->s->msg : "")); + json_object_set_new(ajs, "class", + json_string((pa->s->class_msg) ? pa->s->class_msg : "")); + json_object_set_new(ajs, "pri", json_integer(pa->s->prio)); + + /* alert */ + json_object_set_new(js, "alert", ajs); + + OutputJSONBuffer(js, aft->file_ctx, aft->buffer); + json_object_del(js, "alert"); + } + json_object_clear(js); + json_decref(js); + + return TM_ECODE_OK; +} + +static int AlertJsonDecoderEvent(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) +{ + MemBuffer *buffer = (MemBuffer *)aft->buffer; + int i; + char timebuf[64]; + char *action = "Pass"; + json_t *js; + + if (p->alerts.cnt == 0) + return TM_ECODE_OK; + + MemBufferReset(buffer); + + CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); + + for (i = 0; i < p->alerts.cnt; i++) { + const PacketAlert *pa = &p->alerts.alerts[i]; + if (unlikely(pa->s == NULL)) { + continue; + } + + if ((pa->action & ACTION_DROP) && IS_ENGINE_MODE_IPS(engine_mode)) { + action = "Drop"; + } else if (pa->action & ACTION_DROP) { + action = "wDrop"; + } + + char buf[(32 * 3) + 1]; + PrintRawLineHexBuf(buf, sizeof(buf), GET_PKT_DATA(p), GET_PKT_LEN(p) < 32 ? GET_PKT_LEN(p) : 32); + + js = json_object(); + if (js == NULL) + return TM_ECODE_OK; + + json_t *ajs = json_object(); + if (ajs == NULL) { + json_decref(js); + return TM_ECODE_OK; + } + + /* time & tx */ + json_object_set_new(js, "time", json_string(timebuf)); + + /* tuple */ + //json_object_set_new(js, "srcip", json_string(srcip)); + //json_object_set_new(js, "sp", json_integer(p->sp)); + //json_object_set_new(js, "dstip", json_string(dstip)); + //json_object_set_new(js, "dp", json_integer(p->dp)); + //json_object_set_new(js, "proto", json_integer(proto)); + + json_object_set_new(ajs, "action", json_string(action)); + json_object_set_new(ajs, "gid", json_integer(pa->s->gid)); + json_object_set_new(ajs, "id", json_integer(pa->s->id)); + json_object_set_new(ajs, "rev", json_integer(pa->s->rev)); + json_object_set_new(ajs, "msg", + json_string((pa->s->msg) ? pa->s->msg : "")); + json_object_set_new(ajs, "class", + json_string((pa->s->class_msg) ? pa->s->class_msg : "")); + json_object_set_new(ajs, "pri", json_integer(pa->s->prio)); + + /* alert */ + json_object_set_new(js, "alert", ajs); + OutputJSONBuffer(js, aft->file_ctx, buffer); + json_object_clear(js); + json_decref(js); + } + + return TM_ECODE_OK; +} + +static int JsonAlertLogger(ThreadVars *tv, void *thread_data, const Packet *p) +{ + JsonAlertLogThread *aft = thread_data; + + if (PKT_IS_IPV4(p) || PKT_IS_IPV6(p)) { + return AlertJson(tv, aft, p); + } else if (p->alerts.cnt > 0) { + return AlertJsonDecoderEvent(tv, aft, p); + } + return 0; +} + +static int JsonAlertLogCondition(ThreadVars *tv, const Packet *p) +{ + return (p->alerts.cnt ? TRUE : FALSE); +} + +#define OUTPUT_BUFFER_SIZE 65535 +static TmEcode JsonAlertLogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + JsonAlertLogThread *aft = SCMalloc(sizeof(JsonAlertLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + memset(aft, 0, sizeof(JsonAlertLogThread)); + if(initdata == NULL) + { + SCLogDebug("Error getting context for AlertFastLog. \"initdata\" argument NULL"); + SCFree(aft); + return TM_ECODE_FAILED; + } + + aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (aft->buffer == NULL) { + SCFree(aft); + return TM_ECODE_FAILED; + } + + /** Use the Ouptut Context (file pointer and mutex) */ + aft->file_ctx = ((OutputCtx *)initdata)->data; + + *data = (void *)aft; + return TM_ECODE_OK; +} + +static TmEcode JsonAlertLogThreadDeinit(ThreadVars *t, void *data) +{ + JsonAlertLogThread *aft = (JsonAlertLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + /* clear memory */ + memset(aft, 0, sizeof(JsonAlertLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +static void JsonAlertLogDeInitCtx(OutputCtx *output_ctx) +{ + LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; + LogFileFreeCtx(logfile_ctx); + SCFree(output_ctx); +} + +#define DEFAULT_LOG_FILENAME "alert.json" +/** + * \brief Create a new LogFileCtx for "fast" output style. + * \param conf The configuration node for this output. + * \return A LogFileCtx pointer on success, NULL on failure. + */ +static OutputCtx *JsonAlertLogInitCtx(ConfNode *conf) +{ + LogFileCtx *logfile_ctx = LogFileNewCtx(); + if (logfile_ctx == NULL) { + SCLogDebug("AlertFastLogInitCtx2: Could not create new LogFileCtx"); + return NULL; + } + + if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME) < 0) { + LogFileFreeCtx(logfile_ctx); + return NULL; + } + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) + return NULL; + output_ctx->data = logfile_ctx; + output_ctx->DeInit = JsonAlertLogDeInitCtx; + + return output_ctx; +} + +void TmModuleJsonAlertLogRegister (void) { + tmm_modules[TMM_JSONALERTLOG].name = MODULE_NAME; + tmm_modules[TMM_JSONALERTLOG].ThreadInit = JsonAlertLogThreadInit; + tmm_modules[TMM_JSONALERTLOG].ThreadDeinit = JsonAlertLogThreadDeinit; + tmm_modules[TMM_JSONALERTLOG].cap_flags = 0; + + OutputRegisterPacketModule(MODULE_NAME, "alert-json-log", + JsonAlertLogInitCtx, JsonAlertLogger, JsonAlertLogCondition); +} + +#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 TmModuleJsonAlertLogRegister (void) +{ + tmm_modules[TMM_JSONALERTLOG].name = MODULE_NAME; + tmm_modules[TMM_JSONALERTLOG].ThreadInit = OutputJsonThreadInit; +} + +#endif + diff --git a/src/output-json-alert.h b/src/output-json-alert.h new file mode 100644 index 0000000000..ec8abb7e4e --- /dev/null +++ b/src/output-json-alert.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2013-2014 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 Tom DeCanio + * + * Logs alerts in JSON format. + * + */ + +#ifndef __OUTPUT_JSON_ALERT_H__ +#define __OUTPUT_JSON_ALERT_H__ + +void TmModuleJsonAlertLogRegister (void); + +#endif /* __OUTPUT_JSON_ALERT_H__ */ + diff --git a/src/output-json.c b/src/output-json.c index 2024e891ac..957992f27f 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -355,148 +355,8 @@ TmEcode OutputJSON(json_t *js, void *data, uint64_t *count) return TM_ECODE_OK; } -TmEcode AlertJson(ThreadVars *tv, Packet *p, void *data) -{ - AlertJsonThread *aft = (AlertJsonThread *)data; - MemBuffer *buffer = (MemBuffer *)aft->buffer; - int i; - char *action = "Pass"; - - if (p->alerts.cnt == 0) - return TM_ECODE_OK; - - MemBufferReset(buffer); - - json_t *js = CreateJSONHeader(p, 0); - if (unlikely(js == NULL)) - return TM_ECODE_OK; - - for (i = 0; i < p->alerts.cnt; i++) { - PacketAlert *pa = &p->alerts.alerts[i]; - if (unlikely(pa->s == NULL)) { - continue; - } - - if ((pa->action & ACTION_DROP) && IS_ENGINE_MODE_IPS(engine_mode)) { - action = "Drop"; - } else if (pa->action & ACTION_DROP) { - action = "wDrop"; - } - - json_t *ajs = json_object(); - if (ajs == NULL) { - json_decref(js); - return TM_ECODE_OK; - } - - json_object_set_new(ajs, "action", json_string(action)); - json_object_set_new(ajs, "gid", json_integer(pa->s->gid)); - json_object_set_new(ajs, "id", json_integer(pa->s->id)); - json_object_set_new(ajs, "rev", json_integer(pa->s->rev)); - json_object_set_new(ajs, "msg", - json_string((pa->s->msg) ? pa->s->msg : "")); - json_object_set_new(ajs, "class", - json_string((pa->s->class_msg) ? pa->s->class_msg : "")); - json_object_set_new(ajs, "pri", json_integer(pa->s->prio)); - - /* alert */ - json_object_set_new(js, "alert", ajs); - - OutputJSON(js, aft, &aft->file_ctx->alerts); - json_object_del(js, "alert"); - } - json_object_clear(js); - json_decref(js); - - return TM_ECODE_OK; -} - -TmEcode AlertJsonDecoderEvent(ThreadVars *tv, Packet *p, void *data) -{ - AlertJsonThread *aft = (AlertJsonThread *)data; - MemBuffer *buffer = (MemBuffer *)aft->buffer; - int i; - char timebuf[64]; - char *action = "Pass"; - json_t *js; - - if (p->alerts.cnt == 0) - return TM_ECODE_OK; - - MemBufferReset(buffer); - - CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); - - for (i = 0; i < p->alerts.cnt; i++) { - PacketAlert *pa = &p->alerts.alerts[i]; - if (unlikely(pa->s == NULL)) { - continue; - } - - if ((pa->action & ACTION_DROP) && IS_ENGINE_MODE_IPS(engine_mode)) { - action = "Drop"; - } else if (pa->action & ACTION_DROP) { - action = "wDrop"; - } - - char buf[(32 * 3) + 1]; - PrintRawLineHexBuf(buf, sizeof(buf), GET_PKT_DATA(p), GET_PKT_LEN(p) < 32 ? GET_PKT_LEN(p) : 32); - - js = json_object(); - if (js == NULL) - return TM_ECODE_OK; - - json_t *ajs = json_object(); - if (ajs == NULL) { - json_decref(js); - return TM_ECODE_OK; - } - - /* time & tx */ - json_object_set_new(js, "time", json_string(timebuf)); - - /* tuple */ - //json_object_set_new(js, "srcip", json_string(srcip)); - //json_object_set_new(js, "sp", json_integer(p->sp)); - //json_object_set_new(js, "dstip", json_string(dstip)); - //json_object_set_new(js, "dp", json_integer(p->dp)); - //json_object_set_new(js, "proto", json_integer(proto)); - - json_object_set_new(ajs, "action", json_string(action)); - json_object_set_new(ajs, "gid", json_integer(pa->s->gid)); - json_object_set_new(ajs, "id", json_integer(pa->s->id)); - json_object_set_new(ajs, "rev", json_integer(pa->s->rev)); - json_object_set_new(ajs, "msg", - json_string((pa->s->msg) ? pa->s->msg : "")); - json_object_set_new(ajs, "class", - json_string((pa->s->class_msg) ? pa->s->class_msg : "")); - json_object_set_new(ajs, "pri", json_integer(pa->s->prio)); - - /* alert */ - json_object_set_new(js, "alert", ajs); - OutputJSON(js, aft, &aft->file_ctx->alerts); - json_object_clear(js); - json_decref(js); - } - - return TM_ECODE_OK; -} - TmEcode OutputJson (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { - if (output_flags & OUTPUT_ALERTS) { - - if (PKT_IS_IPV4(p) || PKT_IS_IPV6(p)) { - AlertJson(tv, p, data); - } else if (p->events.cnt > 0) { - AlertJsonDecoderEvent(tv, p, data); - } - } - - if (output_flags & OUTPUT_DNS) { -// OutputDnsLog(tv, p, data); - } - if (output_flags & OUTPUT_DROP) { OutputDropLog(tv, p, data); } @@ -505,10 +365,6 @@ TmEcode OutputJson (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pack OutputFileLog(tv, p, data); } - if (output_flags & OUTPUT_HTTP) { -// OutputHttpLog(tv, p, data); - } - if (output_flags & OUTPUT_TLS) { OutputTlsLog(tv, p, data); } @@ -684,13 +540,6 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) output_flags |= OUTPUT_ALERTS; continue; } - if (strcmp(output->val, "dns") == 0) { - SCLogDebug("Enabling DNS output"); - AppLayerParserRegisterLogger(IPPROTO_TCP,ALPROTO_DNS); - AppLayerParserRegisterLogger(IPPROTO_UDP,ALPROTO_DNS); - output_flags |= OUTPUT_DNS; - continue; - } if (strcmp(output->val, "drop") == 0) { SCLogDebug("Enabling drop output"); output_flags |= OUTPUT_DROP; @@ -703,16 +552,6 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) output_flags |= OUTPUT_FILES; continue; } -#if 0 - if (strcmp(output->val, "http") == 0) { - SCLogDebug("Enabling HTTP output"); - ConfNode *child = ConfNodeLookupChild(output, "http"); - json_ctx->http_ctx = OutputHttpLogInit(child); - AppLayerParserRegisterLogger(IPPROTO_TCP,ALPROTO_HTTP); - output_flags |= OUTPUT_HTTP; - continue; - } -#endif if (strcmp(output->val, "tls") == 0) { SCLogDebug("Enabling TLS output"); ConfNode *child = ConfNodeLookupChild(output, "tls"); diff --git a/src/suricata.c b/src/suricata.c index f2165f9727..6f905d8ba8 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -78,6 +78,7 @@ #include "alert-prelude.h" #include "alert-syslog.h" #include "alert-pcapinfo.h" +#include "output-json-alert.h" #include "log-droplog.h" #include "log-httplog.h" @@ -809,6 +810,10 @@ void RegisterAllModules() /* dns log */ TmModuleLogDnsLogRegister(); TmModuleJsonDnsLogRegister(); + + TmModuleJsonAlertLogRegister(); + + /* log api */ TmModulePacketLoggerRegister(); TmModuleTxLoggerRegister(); TmModuleFileLoggerRegister(); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 8b9712605c..a349f85cf6 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -84,6 +84,7 @@ typedef enum { TMM_TXLOGGER, TMM_FILELOGGER, TMM_FILEDATALOGGER, + TMM_JSONALERTLOG, TMM_JSONHTTPLOG, TMM_JSONDNSLOG, TMM_SIZE,