diff --git a/src/log-pcap.c b/src/log-pcap.c index c7c66dc563..77c760719d 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -26,7 +26,9 @@ */ #include "suricata-common.h" +#include "util-buffer.h" #include "util-fmemopen.h" +#include "stream-tcp-util.h" #ifdef HAVE_LIBLZ4 #include @@ -189,6 +191,7 @@ typedef struct PcapLogData_ { typedef struct PcapLogThreadData_ { PcapLogData *pcap_log; + MemBuffer *buf; } PcapLogThreadData; /* Pattern for extracting timestamp from pcap log files. */ @@ -516,6 +519,48 @@ static inline int PcapWrite( return TM_ECODE_OK; } +struct PcapLogCallbackContext { + PcapLogData *pl; + PcapLogCompressionData *connp; + MemBuffer *buf; +}; + +static int PcapLogSegmentCallback( + const Packet *p, TcpSegment *seg, void *data, const uint8_t *buf, uint32_t buflen) +{ + struct PcapLogCallbackContext *pctx = (struct PcapLogCallbackContext *)data; + + if (seg->pcap_hdr_storage->pktlen) { + pctx->pl->h->ts.tv_sec = seg->pcap_hdr_storage->ts.tv_sec; + pctx->pl->h->ts.tv_usec = seg->pcap_hdr_storage->ts.tv_usec; + pctx->pl->h->len = seg->pcap_hdr_storage->pktlen + buflen; + pctx->pl->h->caplen = seg->pcap_hdr_storage->pktlen + buflen; + MemBufferReset(pctx->buf); + MemBufferWriteRaw(pctx->buf, seg->pcap_hdr_storage->pkt_hdr, seg->pcap_hdr_storage->pktlen); + MemBufferWriteRaw(pctx->buf, buf, buflen); + + PcapWrite(pctx->pl, pctx->connp, (uint8_t *)pctx->buf->buffer, pctx->pl->h->len); + } + return 1; +} + +static void PcapLogDumpSegments( + PcapLogThreadData *td, PcapLogCompressionData *connp, const Packet *p) +{ + uint8_t flag; + /* check which side is packet */ + if (p->flowflags & FLOW_PKT_TOSERVER) { + flag = STREAM_DUMP_TOCLIENT; + } else { + flag = STREAM_DUMP_TOSERVER; + } + flag |= STREAM_DUMP_HEADERS; + + /* Loop on segment from this side */ + struct PcapLogCallbackContext data = { td->pcap_log, connp, td->buf }; + StreamSegmentForEach(p, flag, PcapLogSegmentCallback, (void *)&data); +} + /** * \brief Pcap logging main function * @@ -611,6 +656,19 @@ static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p) PCAPLOG_PROFILE_START; + /* if we are using alerted logging and if packet is first one with alert in flow + * then we need to dump in the pcap the stream acked by the packet */ + if ((p->flags & PKT_FIRST_ALERTS) && (td->pcap_log->conditional == LOGMODE_COND_ALERTS)) { + if (PKT_IS_TCP(p)) { + /* dump fake packets for all segments we have on acked by packet */ +#ifdef HAVE_LIBLZ4 + PcapLogDumpSegments(td, connp, p); +#else + PcapLogDumpSegments(td, NULL, p); +#endif + } + } + #ifdef HAVE_LIBLZ4 ret = PcapWrite(pl, comp, GET_PKT_DATA(p), len); #else @@ -984,6 +1042,12 @@ static TmEcode PcapLogDataInit(ThreadVars *t, const void *initdata, void **data) *data = (void *)td; + if (IsTcpSessionDumpingEnabled()) { + td->buf = MemBufferCreateNew(PCAP_OUTPUT_BUFFER_SIZE); + } else { + td->buf = NULL; + } + if (pl->max_files && (pl->mode == LOGMODE_MULTI || pl->threads == 1)) { #ifdef INIT_RING_BUFFER if (PcapLogInitRingBuffer(td->pcap_log) == TM_ECODE_FAILED) { @@ -1094,6 +1158,9 @@ static TmEcode PcapLogDataDeinit(ThreadVars *t, void *thread_data) PcapLogDataFree(pl); } + if (td->buf) + MemBufferFree(td->buf); + SCFree(td); return TM_ECODE_OK; } @@ -1456,6 +1523,7 @@ static OutputInitResult PcapLogInitCtx(ConfNode *conf) if (s_conditional != NULL) { if (strcasecmp(s_conditional, "alerts") == 0) { pl->conditional = LOGMODE_COND_ALERTS; + EnableTcpSessionDumping(); } else if (strcasecmp(s_conditional, "all") != 0) { FatalError(SC_ERR_INVALID_ARGUMENT, "log-pcap: invalid conditional \"%s\". Valid options: \"all\", " diff --git a/src/log-pcap.h b/src/log-pcap.h index 8b68d43329..ebfe305f44 100644 --- a/src/log-pcap.h +++ b/src/log-pcap.h @@ -28,6 +28,8 @@ #ifndef __LOG_PCAP_H__ #define __LOG_PCAP_H__ +#define PCAP_OUTPUT_BUFFER_SIZE 65535 + void PcapLogRegister(void); void PcapLogProfileSetup(void);