Add special sguil mode to log-pcap to support logging into date based directory structure and rotate when the day passes. Also do not log packets beyond stream reassembly depth and encrypted traffic.

remotes/origin/master-1.1.x
Victor Julien 14 years ago
parent 77505f8873
commit bc7e21aee6

@ -816,6 +816,7 @@ void AddressDebugPrint(Address *);
#define PKT_PSEUDO_STREAM_END 0x0100 /**< Pseudo packet to end the stream */
#define PKT_STREAM_MODIFIED 0x0200 /**< Packet is modified by the stream engine, we need to recalc the csum and reinject/replace */
#define PKT_MARK_MODIFIED 0x0400 /**< Packet mark is modified */
#define PKT_STREAM_NOPCAPLOG 0x0800 /**< Exclude packet from pcap logging as it's part of a stream that has reassembly depth reached. */
/** \brief return 1 if the packet is a pseudo packet */
#define PKT_IS_PSEUDOPKT(p) ((p)->flags & PKT_PSEUDO_STREAM_END)

@ -57,6 +57,12 @@
#define MIN_LIMIT 1
#define DEFAULT_LIMIT 100
#define LOGMODE_NORMAL 0
#define LOGMODE_SGUIL 1
static int g_logpcap_mode = LOGMODE_NORMAL;
static char g_logpcap_sguil_base_dir[PATH_MAX] = "";
/*prototypes*/
TmEcode PcapLog (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
TmEcode PcapLogThreadInit(ThreadVars *, void *, void **);
@ -75,6 +81,8 @@ typedef struct PcapLogThread_ {
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 */
int prev_day; /**< last day, for finding out when
to rotate in sguil mode */
} PcapLogThread;
void TmModulePcapLogRegister (void) {
@ -139,19 +147,33 @@ TmEcode PcapLog (ThreadVars *t, Packet *p, void *data, PacketQueue *pq, PacketQu
{
size_t len;
PcapLogThread *pl = (PcapLogThread *)data;
int rotate = 0;
if (pl == NULL) {
return TM_ECODE_FAILED;
}
if (p->flags & PKT_PSEUDO_STREAM_END || p->flags & PKT_STREAM_NOPCAPLOG) {
return TM_ECODE_OK;
}
pl->h->ts.tv_sec = p->ts.tv_sec;
pl->h->ts.tv_usec = p->ts.tv_usec;
pl->h->caplen = GET_PKT_LEN(p);
pl->h->len = GET_PKT_LEN(p);
len = sizeof(*pl->h) + GET_PKT_LEN(p);
if (g_logpcap_mode == LOGMODE_SGUIL) {
struct tm local_tm;
struct tm *tms = (struct tm *)localtime_r(&p->ts.tv_sec, &local_tm);
if (tms->tm_mday != pl->prev_day) {
rotate = 1;
pl->prev_day = tms->tm_mday;
}
}
SCMutexLock(&pl->file_ctx->fp_mutex);
if ((pl->size_current + len) > pl->file_ctx->size_limit) {
if ((pl->size_current + len) > pl->file_ctx->size_limit || rotate) {
if (PcapLogRotateFile(t,pl) < 0)
{
SCMutexUnlock(&pl->file_ctx->fp_mutex);
@ -216,6 +238,13 @@ TmEcode PcapLogThreadInit(ThreadVars *t, void *initdata, void **data)
pl->pcap_dead_handle = NULL;
pl->pcap_dumper = NULL;
struct timeval ts;
memset(&ts, 0x00, sizeof(struct timeval));
TimeGet(&ts);
struct tm local_tm;
struct tm *tms = (struct tm *)localtime_r(&ts.tv_sec, &local_tm);
pl->prev_day = tms->tm_mday;
*data = (void *)pl;
return TM_ECODE_OK;
}
@ -275,9 +304,9 @@ OutputCtx *PcapLogInitCtx(ConfNode *conf)
file_ctx->prefix = SCStrdup(filename);
const char *s_limit = NULL;
uint32_t limit = DEFAULT_LIMIT;
if (conf != NULL) {
const char *s_limit = NULL;
s_limit = ConfNodeLookupChildValue(conf, "limit");
if (s_limit != NULL) {
if (ByteExtractStringUint32(&limit, 10, 0, s_limit) == -1) {
@ -296,8 +325,34 @@ OutputCtx *PcapLogInitCtx(ConfNode *conf)
}
file_ctx->size_limit = limit * 1024 * 1024;
ret = PcapLogOpenFileCtx(file_ctx, filename);
if (conf != NULL) {
const char *s_mode = NULL;
s_mode = ConfNodeLookupChildValue(conf, "mode");
if (s_mode != NULL) {
if (strcasecmp(s_mode, "sguil") == 0) {
g_logpcap_mode = LOGMODE_SGUIL;
}
}
if (g_logpcap_mode == LOGMODE_SGUIL) {
const char *s_sguil_base = NULL;
s_sguil_base = ConfNodeLookupChildValue(conf, "sguil_base_dir");
if (s_sguil_base == NULL) {
SCLogError(SC_ERR_LOGPCAP_SGUIL_BASE_DIR_MISSING,
"log-pcap \"sguil\" mode requires \"sguil_base_dir\" "
"option to be set.");
exit(EXIT_FAILURE);
}
strlcpy(g_logpcap_sguil_base_dir,
s_sguil_base, sizeof(g_logpcap_sguil_base_dir));
}
}
SCLogInfo("using %s logging", g_logpcap_mode == LOGMODE_SGUIL ?
"Sguil compatible" : "normal");
ret = PcapLogOpenFileCtx(file_ctx, filename);
if (ret < 0)
return NULL;
@ -336,7 +391,7 @@ int PcapLogOpenFileCtx(LogFileCtx *file_ctx, const char *prefix)
{
char *filename = NULL;
if (file_ctx->filename != NULL)
if (file_ctx->filename != NULL)
filename = file_ctx->filename;
else {
filename = file_ctx->filename = SCMalloc(PATH_MAX);
@ -350,15 +405,33 @@ int PcapLogOpenFileCtx(LogFileCtx *file_ctx, const char *prefix)
memset(&ts, 0x00, sizeof(struct timeval));
TimeGet(&ts);
/* create the filename to use */
if (prefix[0] == '/') {
snprintf(filename, PATH_MAX, "%s.%" PRIu32, prefix, (uint32_t)ts.tv_sec);
} else {
char *log_dir;
if (ConfGet("default-log-dir", &log_dir) != 1)
log_dir = DEFAULT_LOG_DIR;
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);
if (g_logpcap_mode == LOGMODE_SGUIL) {
struct tm local_tm;
struct tm *tms = (struct tm *)localtime_r(&ts.tv_sec, &local_tm);
char dirname[32], dirfull[PATH_MAX] = "";
snprintf(dirname, sizeof(dirname), "%04d-%02d-%02d",
tms->tm_year + 1900, tms->tm_mon + 1, tms->tm_mday);
/* create the filename to use */
snprintf(dirfull, PATH_MAX, "%s/%s", g_logpcap_sguil_base_dir, dirname);
/* if mkdir fails file open will fail, so deal with errors there */
(void)mkdir(dirfull, 0700);
snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32, dirfull, prefix, (uint32_t)ts.tv_sec);
} else {
/* create the filename to use */
if (prefix[0] == '/') {
snprintf(filename, PATH_MAX, "%s.%" PRIu32, prefix, (uint32_t)ts.tv_sec);
} else {
snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32, log_dir, prefix, (uint32_t)ts.tv_sec);
}
}
return 0;

@ -3320,6 +3320,23 @@ static int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt,
StreamTcpInlineRecalcCsum(p);
}
/* check for conditions that may make us not want to log this packet */
if (ssn != NULL) {
/* streams that hit depth */
if ((ssn->client.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED ||
ssn->server.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED))
{
p->flags |= PKT_STREAM_NOPCAPLOG;
}
/* encrypted packets */
if ((PKT_IS_TOSERVER(p) && ssn->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
(PKT_IS_TOCLIENT(p) && ssn->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY))
{
p->flags |= PKT_STREAM_NOPCAPLOG;
}
}
SCReturnInt(0);
error:

@ -201,6 +201,7 @@ const char * SCErrorToString(SCError err)
CASE_CODE (SC_ERR_HTTP_COOKIE_NEEDS_PRECEEDING_CONTENT);
CASE_CODE (SC_ERR_HTTP_COOKIE_INCOMPATIBLE_WITH_RAWBYTES);
CASE_CODE (SC_ERR_HTTP_COOKIE_RELATIVE_MISSING);
CASE_CODE (SC_ERR_LOGPCAP_SGUIL_BASE_DIR_MISSING);
default:
return "UNKNOWN_ERROR";

@ -212,6 +212,7 @@ typedef enum {
SC_ERR_HTTP_COOKIE_NEEDS_PRECEEDING_CONTENT,
SC_ERR_HTTP_COOKIE_INCOMPATIBLE_WITH_RAWBYTES,
SC_ERR_HTTP_COOKIE_RELATIVE_MISSING,
SC_ERR_LOGPCAP_SGUIL_BASE_DIR_MISSING,
} SCError;
const char *SCErrorToString(SCError);

@ -73,7 +73,20 @@ outputs:
filename: http.log
append: yes
# Packet log... log packets in pcap format.
# Packet log... log packets in pcap format. 2 modes of operation: "normal"
# and "sguil".
#
# In normal mode a pcap file "filename" is created in the default-log-dir,
# or if filename is an absolute path a that path. In Sguil mode "sguil_base_dir"
# indicates the base directory. In this base dir the pcaps are created in the
# directory structure Sguil expects:
#
# $sguil_base_dir/YYYY-MM-DD/$filename.<timestamp>
#
# By default all packets are logged except:
# - TCP streams beyond stream.reassembly.depth
# - encrypted streams after the key exchange
#
- pcap-log:
enabled: no
filename: log.pcap
@ -81,6 +94,9 @@ outputs:
# Limit in MB.
#limit: 32
#mode: sguil # "normal" (default) or sguil.
#sguil_base_dir: /nsm_data/
# a full alerts log containing much information for signature writers
# or for investigating suspected false positives.
- alert-debug:

Loading…
Cancel
Save