From 023a0f94a2a31f140fe151979cae598c7446c0e9 Mon Sep 17 00:00:00 2001 From: William Metcalf Date: Mon, 19 Jul 2010 21:35:18 -0500 Subject: [PATCH] first stab at pcap logging no rotating buff etc --- src/Makefile.am | 1 + src/log-pcap.c | 300 +++++++++++++++++++++++++++++++++++++++++++++++ src/log-pcap.h | 13 ++ src/suricata.c | 2 + src/tm-modules.h | 1 + suricata.yaml | 5 +- 6 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 src/log-pcap.c create mode 100644 src/log-pcap.h diff --git a/src/Makefile.am b/src/Makefile.am index e33aabdc76..6f98d9f604 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -210,6 +210,7 @@ alert-unified2-alert.c alert-unified2-alert.h \ alert-syslog.c alert-syslog.h \ log-droplog.c log-droplog.h \ log-httplog.c log-httplog.h \ +log-pcap.c log-pcap.h \ stream.c stream.h \ stream-tcp.c stream-tcp.h stream-tcp-private.h \ stream-tcp-reassemble.c stream-tcp-reassemble.h \ diff --git a/src/log-pcap.c b/src/log-pcap.c new file mode 100644 index 0000000000..9d97c4e1dc --- /dev/null +++ b/src/log-pcap.c @@ -0,0 +1,300 @@ +/* Copyright (c) 2009 Open Information Security Foundation */ + +/** \file + * \author William Metcalf + */ +#if LIBPCAP_VERSION_MAJOR == 1 +#include +#else +#include +#endif + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "flow.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-modules.h" + +#include "util-unittest.h" +#include "log-pcap.h" +#include "decode-ipv4.h" + +#include "util-error.h" +#include "util-debug.h" +#include "util-time.h" +#include "util-byte.h" + +#include "source-pcap.h" + +#include "output.h" + +#define DEFAULT_LOG_FILENAME "pcaplog" +#define MODULE_NAME "PcapLog" +#define MIN_LIMIT 1 +#define DEFAULT_LIMIT 100 + +/*prototypes*/ +TmEcode PcapLog (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); +TmEcode PcapLogThreadInit(ThreadVars *, void *, void **); +TmEcode PcapLogThreadDeinit(ThreadVars *, void *); +int PcapLogOpenFileCtx(LogFileCtx *, const char *); +static void PcapLogFileDeInitCtx(OutputCtx *); + +/** + * PcapLog thread vars + * + * Used for storing file options. + */ +typedef struct PcapLogThread_ { + LogFileCtx *file_ctx; /** LogFileCtx pointer */ + uint32_t size_current; /**< file current size */ + pcap_t *pcap_dead_handle; /**< pcap_dumper_t needs a handle */ + pcap_dumper_t *pcap_dumper; /**< actually writes the packets */ + struct pcap_pkthdr *h; /**< pcap header struct */ +} PcapLogThread; + +void TmModulePcapLogRegister (void) { + tmm_modules[TMM_PCAPLOG].name = MODULE_NAME; + tmm_modules[TMM_PCAPLOG].ThreadInit = PcapLogThreadInit; + tmm_modules[TMM_PCAPLOG].Func = PcapLog; + tmm_modules[TMM_PCAPLOG].ThreadDeinit = PcapLogThreadDeinit; + tmm_modules[TMM_PCAPLOG].RegisterTests = NULL; + OutputRegisterModule(MODULE_NAME, "pcap-log", PcapLogInitCtx); +} + +/** + * \brief Function to close pcaplog file + * + * \param t Thread Variable containing input/output queue, cpu affinity etc. + * \param pl PcapLog thread variable. + */ + +int PcapLogCloseFile(ThreadVars *t, PcapLogThread *pl) { + pcap_dump_close(pl->pcap_dumper); + pl->size_current = 0; + pl->pcap_dumper = NULL; + return 0; +} + +/** + * \brief Function to rotate pcaplog file + * + * \param t Thread Variable containing input/output queue, cpu affinity etc. + * \param pl PcapLog thread variable. + * \retval 0 on succces + * \retval -1 on failure + */ + +int PcapLogRotateFile(ThreadVars *t, PcapLogThread *pl) { + if (PcapLogCloseFile(t,pl) < 0) { + SCLogInfo("Error: PcapLogCloseFile failed"); + return -1; + } + if (PcapLogOpenFileCtx(pl->file_ctx,pl->file_ctx->prefix) < 0) { + SCLogInfo("Error: PcapLogOpenFileCtx, open new log file failed"); + return -1; + } + return 0; +} + +TmEcode PcapLog (ThreadVars *t, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) +{ + int len; + PcapLogThread *pl = (PcapLogThread *)data; + + pl->h->ts.tv_sec = p->ts.tv_sec; + pl->h->ts.tv_usec = p->ts.tv_usec; + pl->h->caplen = p->pktlen; + pl->h->len = p->pktlen; + len = sizeof(*pl->h) + p->pktlen; + + SCMutexLock(&pl->file_ctx->fp_mutex); + if ((pl->size_current + len) > pl->file_ctx->size_limit) { + if (PcapLogRotateFile(t,pl) < 0) + { + SCMutexUnlock(&pl->file_ctx->fp_mutex); + SCLogInfo("rotation of pcap failed"); + return TM_ECODE_FAILED; + } + } + SCMutexUnlock(&pl->file_ctx->fp_mutex); + + /* XXX pcap handles, nfq, pfring, can only have one link type ipfw? we do this here as we don't know the link type until we get our first packet */ + if(pl->pcap_dead_handle == NULL){ + SCLogDebug("Setting pcap-log link type to %u", p->datalink); + if((pl->pcap_dead_handle=pcap_open_dead(p->datalink,LIBPCAP_SNAPLEN)) == NULL){ + SCLogDebug("Error opening dead pcap handle"); + return TM_ECODE_FAILED; + } + } + /*XXX LogfileCtx setup currently doesn't allow thread vars so we open the handle here */ + if(pl->pcap_dumper == NULL){ + if((pl->pcap_dumper=pcap_dump_open(pl->pcap_dead_handle, pl->file_ctx->filename)) == NULL){ + SCLogInfo("Error opening dump file %s",pcap_geterr(pl->pcap_dead_handle)); + return TM_ECODE_FAILED; + } + } + + pcap_dump((u_char *)pl->pcap_dumper,pl->h,p->pkt); + pl->size_current += len; + SCLogDebug("%u %u",pl->size_current,pl->file_ctx->size_limit); + return TM_ECODE_OK; +} + +TmEcode PcapLogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + PcapLogThread *pl = malloc(sizeof(PcapLogThread)); + if (pl == NULL) { + return TM_ECODE_FAILED; + } + memset(pl, 0, sizeof(PcapLogThread)); + + pl->h = malloc(sizeof(*pl->h)); + if (pl->h == NULL) { + return TM_ECODE_FAILED; + } + + if(initdata == NULL) + { + SCLogDebug("Error getting context for PcapLog. \"initdata\" argument NULL"); + return TM_ECODE_FAILED; + } + + /** Use the Ouptut Context (file pointer and mutex) */ + pl->file_ctx = ((OutputCtx*)initdata)->data; + + pl->pcap_dead_handle = NULL; + pl->pcap_dumper = NULL; + + *data = (void *)pl; + return TM_ECODE_OK; +} + +/** + * \brief Thread deinit function. + * + * \param t Thread Variable containing input/output queue, cpu affinity etc. + * \param data PcapLog thread data. + * \retval TM_ECODE_OK on succces + * \retval TM_ECODE_FAILED on failure + */ + +TmEcode PcapLogThreadDeinit(ThreadVars *t, void *data) +{ + PcapLogThread *pl = (PcapLogThread *)data; + if (pl == NULL) { + goto error; + } + + /* clear memory */ + memset(pl, 0, sizeof(PcapLogThread)); + free(pl); + return TM_ECODE_OK; + +error: + /* clear memory */ + if (pl != NULL) { + memset(pl, 0, sizeof(PcapLogThread)); + free(pl); + } + return TM_ECODE_FAILED; +} + +/** \brief Create a new LogFileCtx from the provided ConfNode. + * \param conf The configuration node for this output. + * \return NULL if failure, LogFileCtx* to the file_ctx if succesful + * */ +OutputCtx *PcapLogInitCtx(ConfNode *conf) +{ + int ret=0; + LogFileCtx* file_ctx=LogFileNewCtx(); + + if(file_ctx == NULL) + { + SCLogDebug( "PcapLogInitCtx: " + "Couldn't create new file_ctx"); + return NULL; + } + + const char *filename = NULL; + if (conf != NULL) { /* To faciliate unit tests. */ + filename = ConfNodeLookupChildValue(conf, "filename"); + } + if (filename == NULL) + filename = DEFAULT_LOG_FILENAME; + file_ctx->prefix = SCStrdup(filename); + + const char *s_limit = NULL; + uint32_t limit = DEFAULT_LIMIT; + if (conf != NULL) { + s_limit = ConfNodeLookupChildValue(conf, "limit"); + if (s_limit != NULL) { + if (ByteExtractStringUint32(&limit, 10, 0, s_limit) == -1) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "Fail to initialize pcap-log output, invalid limit: %s", + s_limit); + exit(EXIT_FAILURE); + } + if (limit < MIN_LIMIT) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "Fail to initialize pcap-log output, limit less than " + "allowed minimum."); + exit(EXIT_FAILURE); + } + } + } + file_ctx->size_limit = limit * 1024 * 1024; + + ret=PcapLogOpenFileCtx(file_ctx, filename); + + if(ret < 0) + return NULL; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (output_ctx == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for OutputCtx."); + exit(EXIT_FAILURE); + } + output_ctx->data = file_ctx; + output_ctx->DeInit = PcapLogFileDeInitCtx; + + return output_ctx; +} + +static void PcapLogFileDeInitCtx(OutputCtx *output_ctx) +{ + LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; + LogFileFreeCtx(logfile_ctx); + free(output_ctx); +} + +/** \brief Read the config set the file pointer, open the file + * \param file_ctx pointer to a created LogFileCtx using LogFileNewCtx() + * \param prefix Prefix of the log file. + * \return -1 if failure, 0 if succesful + * */ +int PcapLogOpenFileCtx(LogFileCtx *file_ctx, const char *prefix) +{ + char *filename = NULL; + if (file_ctx->filename != NULL) + filename = file_ctx->filename; + else + filename = file_ctx->filename = malloc(PATH_MAX); /* XXX some sane default? */ + + /** get the time so we can have a filename with seconds since epoch */ + struct timeval ts; + memset(&ts, 0x00, sizeof(struct timeval)); + TimeGet(&ts); + + /* create the filename to use */ + char *log_dir; + if (ConfGet("default-log-dir", &log_dir) != 1) + log_dir = DEFAULT_LOG_DIR; + + snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32, log_dir, prefix, (uint32_t)ts.tv_sec); + return 0; +} diff --git a/src/log-pcap.h b/src/log-pcap.h new file mode 100644 index 0000000000..65dfe93ce3 --- /dev/null +++ b/src/log-pcap.h @@ -0,0 +1,13 @@ +/** Copyright (c) 2009 Open Information Security Foundation + * + * \author Breno Silva + */ + +#ifndef __PCAP_LOG_ALERT_H__ +#define __PCAP_LOG_ALERT_H__ + +void TmModulePcapLogRegister (void); +OutputCtx *PcapLogInitCtx(ConfNode *); + + +#endif /* __PCAP_LOG_ALERT_H__ */ diff --git a/src/suricata.c b/src/suricata.c index 2fab0a093f..340982b120 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -83,6 +83,7 @@ #include "log-droplog.h" #include "log-httplog.h" +#include "log-pcap.h" #include "stream-tcp.h" @@ -1041,6 +1042,7 @@ int main(int argc, char **argv) TmModuleLogHttpLogRegister(); TmModuleLogHttpLogIPv4Register(); TmModuleLogHttpLogIPv6Register(); + TmModulePcapLogRegister(); #ifdef __SC_CUDA_SUPPORT__ TmModuleCudaMpmB2gRegister(); TmModuleCudaPacketBatcherRegister(); diff --git a/src/tm-modules.h b/src/tm-modules.h index 01e5e42ebb..e77bc0e2a1 100644 --- a/src/tm-modules.h +++ b/src/tm-modules.h @@ -76,6 +76,7 @@ enum { TMM_LOGHTTPLOG, TMM_LOGHTTPLOG4, TMM_LOGHTTPLOG6, + TMM_PCAPLOG, TMM_STREAMTCP, TMM_DECODEIPFW, TMM_VERDICTIPFW, diff --git a/suricata.yaml b/suricata.yaml index a291afed89..d9968efa8e 100644 --- a/suricata.yaml +++ b/suricata.yaml @@ -73,10 +73,13 @@ outputs: filename: http.log append: yes + - pcap-log: + enabled: no + filename: log.pcap # a full alerts log containing much information for signature writers # or for investigating suspected false positives. - alert-debug: - enabled: no + enabled: yes filename: alert-debug.log append: yes