From 27f1d88374c199da18d3acb185ad17d174e9a877 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 29 Sep 2011 14:48:27 +0200 Subject: [PATCH] Add pcap-info alert format. This patch adds a new alert format called pcap-info. It aims at providing an easy to parse one-line per-alert format containing the packet id in the parsed pcap for each alert. This permit to add information inside the pcap parser. This format is made to be used with suriwire which is a plugin for wireshark. Its target is to enable the display of suricata results inside wireshark. This format doesn't use append mode per default because a clean file is needed to operate with wireshark. The format is a list of values separated by ':': Packet number:GID of matching signature:SID of signature:REV of signature:Flow:To Server:To Client:0:0:Message of signature The two zero are not yet used values. Candidate for usage is the part of the packet that matched the signature. --- src/Makefile.am | 1 + src/alert-pcapinfo.c | 237 ++++++++++++++++++++++++++++++++++++++++ src/alert-pcapinfo.h | 30 +++++ src/suricata.c | 2 + src/tm-threads-common.h | 1 + suricata.yaml | 7 ++ 6 files changed, 278 insertions(+) create mode 100644 src/alert-pcapinfo.c create mode 100644 src/alert-pcapinfo.h diff --git a/src/Makefile.am b/src/Makefile.am index 59522c0feb..1145471b79 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -228,6 +228,7 @@ alert-unified-log.c alert-unified-log.h \ alert-unified-alert.c alert-unified-alert.h \ alert-unified2-alert.c alert-unified2-alert.h \ alert-syslog.c alert-syslog.h \ +alert-pcapinfo.c alert-pcapinfo.h \ log-droplog.c log-droplog.h \ log-httplog.c log-httplog.h \ log-pcap.c log-pcap.h \ diff --git a/src/alert-pcapinfo.c b/src/alert-pcapinfo.c new file mode 100644 index 0000000000..e487ccfc83 --- /dev/null +++ b/src/alert-pcapinfo.c @@ -0,0 +1,237 @@ +/* Copyright (C) 2011 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 Eric Leblond + * + * Logs alerts in a line based text format suitable for interaction + * with wireshark or an other pcap file analysis tools. + * + * The format of the logging is: + * Packet number:GID of matching signature:SID of signature:REV of signature:Flow:To Server:To Client:0:0:Signature Message + * The two zeros are reserved for upcoming usage (probably byte start + * and byte end of payload) + */ + +#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 "util-classification-config.h" + +#include "output.h" +#include "alert-pcapinfo.h" + +#include "util-mpm-b2g-cuda.h" +#include "util-cuda-handlers.h" +#include "util-privs.h" +#include "util-print.h" +#include "util-proto-name.h" +#include "util-optimize.h" + +#define DEFAULT_LOG_FILENAME "alert-pcapinfo.log" +/* We need a new file for each pcap */ +#define DEFAULT_PCAPINFO_MODE_APPEND "no" + +#define MODULE_NAME "AlertPcapInfo" + +TmEcode AlertPcapInfo (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); +TmEcode AlertPcapInfoThreadInit(ThreadVars *, void *, void **); +TmEcode AlertPcapInfoThreadDeinit(ThreadVars *, void *); +void AlertPcapInfoExitPrintStats(ThreadVars *, void *); +static int AlertPcapInfoOpenFileCtx(LogFileCtx *, const char *, const char *); +static void AlertPcapInfoDeInitCtx(OutputCtx *); + +void TmModuleAlertPcapInfoRegister (void) { + tmm_modules[TMM_ALERTPCAPINFO].name = MODULE_NAME; + tmm_modules[TMM_ALERTPCAPINFO].ThreadInit = AlertPcapInfoThreadInit; + tmm_modules[TMM_ALERTPCAPINFO].Func = AlertPcapInfo; + tmm_modules[TMM_ALERTPCAPINFO].ThreadExitPrintStats = AlertPcapInfoExitPrintStats; + tmm_modules[TMM_ALERTPCAPINFO].ThreadDeinit = AlertPcapInfoThreadDeinit; + tmm_modules[TMM_ALERTPCAPINFO].RegisterTests = NULL; + tmm_modules[TMM_ALERTPCAPINFO].cap_flags = 0; + + OutputRegisterModule(MODULE_NAME, "pcap-info", AlertPcapInfoInitCtx); +} + +typedef struct AlertPcapInfoThread_ { + /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ + LogFileCtx* file_ctx; +} AlertPcapInfoThread; + + +TmEcode AlertPcapInfo (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) +{ + AlertPcapInfoThread *aft = (AlertPcapInfoThread *)data; + int i; + + + /* logging is useless if we don't have pcap number */ + if ((p->pcap_cnt != 0) && (p->alerts.cnt > 0)) { + SCMutexLock(&aft->file_ctx->fp_mutex); + /* only count logged alert */ + aft->file_ctx->alerts += p->alerts.cnt; + for (i = 0; i < p->alerts.cnt; i++) { + PacketAlert *pa = &p->alerts.alerts[i]; + + fprintf(aft->file_ctx->fp, "%ld:%d:%d:%d:%d:%d:%d:0:0:%s\n", + p->pcap_cnt, pa->s->gid, pa->s->id, + pa->s->rev, pa->alert_msg ? 1 : 0, + p->flowflags & FLOW_PKT_TOSERVER ? 1 : 0, + p->flowflags & FLOW_PKT_TOCLIENT ? 1 : 0, + pa->s->msg); + } + SCMutexUnlock(&aft->file_ctx->fp_mutex); + } + + return TM_ECODE_OK; +} + +TmEcode AlertPcapInfoThreadInit(ThreadVars *t, void *initdata, void **data) +{ + AlertPcapInfoThread *aft = SCMalloc(sizeof(AlertPcapInfoThread)); + if (aft == NULL) + return TM_ECODE_FAILED; + memset(aft, 0, sizeof(AlertPcapInfoThread)); + if(initdata == NULL) + { + SCLogDebug("Error getting context for AlertPcapInfo. \"initdata\" argument 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; +} + +TmEcode AlertPcapInfoThreadDeinit(ThreadVars *t, void *data) +{ + AlertPcapInfoThread *aft = (AlertPcapInfoThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + /* clear memory */ + memset(aft, 0, sizeof(AlertPcapInfoThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +void AlertPcapInfoExitPrintStats(ThreadVars *tv, void *data) { + AlertPcapInfoThread *aft = (AlertPcapInfoThread *)data; + if (aft == NULL) { + return; + } + + SCLogInfo("(%s) Alerts %" PRIu64 "", tv->name, aft->file_ctx->alerts); +} + +/** + * \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. + */ +OutputCtx *AlertPcapInfoInitCtx(ConfNode *conf) +{ + LogFileCtx *logfile_ctx = LogFileNewCtx(); + if (logfile_ctx == NULL) { + SCLogDebug("AlertPcapInfoInitCtx2: Could not create new LogFileCtx"); + return NULL; + } + + const char *filename = ConfNodeLookupChildValue(conf, "filename"); + if (filename == NULL) + filename = DEFAULT_LOG_FILENAME; + + const char *mode = ConfNodeLookupChildValue(conf, "append"); + if (mode == NULL) + mode = DEFAULT_PCAPINFO_MODE_APPEND; + + if (AlertPcapInfoOpenFileCtx(logfile_ctx, filename, mode) < 0) { + LogFileFreeCtx(logfile_ctx); + return NULL; + } + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (output_ctx == NULL) + return NULL; + output_ctx->data = logfile_ctx; + output_ctx->DeInit = AlertPcapInfoDeInitCtx; + + SCLogInfo("Fast log output initialized, filename: %s", filename); + + return output_ctx; +} + +static void AlertPcapInfoDeInitCtx(OutputCtx *output_ctx) +{ + LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; + LogFileFreeCtx(logfile_ctx); + SCFree(output_ctx); +} + +/** \brief Read the config set the file pointer, open the file + * \param file_ctx pointer to a created LogFileCtx using LogFileNewCtx() + * \param filename name of log file + * \param mode append mode (bool) + * \return -1 if failure, 0 if succesful + * */ +static int AlertPcapInfoOpenFileCtx(LogFileCtx *file_ctx, const char *filename, + const char *mode) +{ + char log_path[PATH_MAX]; + char *log_dir; + + if (ConfGet("default-log-dir", &log_dir) != 1) + log_dir = DEFAULT_LOG_DIR; + + snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename); + + if (ConfValIsTrue(mode)) { + file_ctx->fp = fopen(log_path, "a"); + } else { + file_ctx->fp = fopen(log_path, "w"); + } + + if (file_ctx->fp == NULL) { + SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", log_path, + strerror(errno)); + return -1; + } + + return 0; +} diff --git a/src/alert-pcapinfo.h b/src/alert-pcapinfo.h new file mode 100644 index 0000000000..871c23f512 --- /dev/null +++ b/src/alert-pcapinfo.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2011 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 Eric Leblond + */ + +#ifndef __ALERT_PCAPINFO_H__ +#define __ALERT_PCAPINFO_H__ + +void TmModuleAlertPcapInfoRegister (void); +OutputCtx *AlertPcapInfoInitCtx(ConfNode *); + +#endif /* __ALERT_PCAPINFO_H__ */ diff --git a/src/suricata.c b/src/suricata.c index 7cd32ed84e..05b1317c60 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -82,6 +82,7 @@ #include "alert-debuglog.h" #include "alert-prelude.h" #include "alert-syslog.h" +#include "alert-pcapinfo.h" #include "log-droplog.h" #include "log-httplog.h" @@ -1208,6 +1209,7 @@ int main(int argc, char **argv) TmModuleAlertUnifiedAlertRegister(); TmModuleUnified2AlertRegister(); TmModuleAlertSyslogRegister(); + TmModuleAlertPcapInfoRegister(); TmModuleLogDropLogRegister(); TmModuleStreamTcpRegister(); TmModuleLogHttpLogRegister(); diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 7b075daeb9..d506cd123c 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -72,6 +72,7 @@ typedef enum { TMM_DECODEERFDAG, TMM_RECEIVEAFP, TMM_DECODEAFP, + TMM_ALERTPCAPINFO, TMM_SIZE, } TmmId; diff --git a/suricata.yaml b/suricata.yaml index 9214c3fdbb..03c4d1d3ee 100644 --- a/suricata.yaml +++ b/suricata.yaml @@ -77,6 +77,13 @@ outputs: filename: http.log append: yes + # a line based log to used with pcap file study. + # this module is dedicated to offline pcap parsing (empty output + # if used with an other kind of input). It can interoperate with + # pcap parser like wireshark via the suriwire plugin. + - pcap-info: + enabled: no + # Packet log... log packets in pcap format. 2 modes of operation: "normal" # and "sguil". #