Snort mailing list archives
Re: RE: Network Behaviour Anomoly Detection
From: "Lawrence Reed" <Lawrence.Reed () noaa gov>
Date: Wed, 13 Oct 2004 12:03:07 +0000
Larry Reed wrote:
I have a chunk of code to do just that. It was written some time ago for BY 0.1.0. Spits out the stream stats in a csv format, similar to alert_csv output.b If anyone is interested I'll clean it up for BY 0.2.0 and post it.
Someone expressed interest so here it is:This patch will allow BY 0.2.0 to read snort stream stat unified files. The output is written to a csv file as define in barynard.conf. The default filename is stats-csv.out and the default format is:
starttime, endtime, client-ip, client-port, server-ip, server-port, server-bytes, server-packets, client-bytes,client-packets
My barnyard.conf contains only two lines: processor dp_stream_stat output stream_stat_csv The files are created with the following snort.conf entry: preprocessor stream4: disable_evasion_alerts, keepstats binary I patched a few files and created two new files: Patched: /barnyard-0.2.0/src/input-plugins/dp_stream_stat.h /barnyard-0.2.0/src/output-plugins/op_plugbase.c /barnyard-0.2.0/src/output-plugins/Makefile.in New: /barnyard-0.2.0/src/output-plugins/op_stream_stat_csv.c /barnyard-0.2.0/src/output-plugins/op_stream_stat_csv.hI have been using this code for several weeks. It works with my configuration. I have not tested everything and consider this beta code.
The patches were created from BY 0.2.0 build 32. Use at your own risk. Larry
--- ../../../barnyard-0.2.0/src/output-plugins/op_stream_stat_csv.h Thu Jan 1 00:00:00 1970 +++ op_stream_stat_csv.h Fri Mar 26 04:15:17 2004 @@ -0,0 +1,9 @@ + + +#ifndef __OP_STREAM_STAT_CSV_H__ +#define __OP_STREAM_STAT_CSV_H__ + +void OpStreamStatCSV_Init(); + +#endif /* __OP_STREAM_STAT_CSV_H__ */ +
--- ../../../barnyard-0.2.0/src/input-plugins/dp_stream_stat.h Fri Feb 20 01:59:48 2004
+++ dp_stream_stat.h Wed Sep 22 12:21:10 2004
@@ -18,6 +18,7 @@
#include <sys/types.h>
#define STREAM_STAT_MAGIC 0xDEAD5747 /* dead alert (ok, so it's stupid) */
+#define STREAM_STAT_MAGIC 0xdead029a /* dead alert (ok, so it's stupid) */
typedef struct _StreamStatFileHeader
{
--- ../../../barnyard-0.2.0/src/output-plugins/Makefile.in Sat May 1 16:52:16 2004 +++ Makefile.in Wed Jul 14 20:51:07 2004 @@ -87,7 +87,7 @@ libop_a_LIBADD = libop_a_OBJECTS = op_decode.o op_fast.o op_plugbase.o op_logdump.o \ op_alert_syslog.o op_log_pcap.o op_acid_db.o op_alert_csv.o op_sguil.o \ -op_alert_syslog2.o op_alert_console.o +op_alert_syslog2.o op_alert_console.o op_stream_stat_csv.o AR = ar CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
--- ../../../barnyard-0.2.0/src/output-plugins/op_plugbase.c Mon Mar 29 00:14:19 2004
+++ op_plugbase.c Wed Jul 14 20:47:27 2004
@@ -33,6 +33,7 @@
#include "op_alert_csv.h"
#include "op_alert_syslog2.h"
#include "op_alert_console.h"
+#include "op_stream_stat_csv.h"
/* ----------------------- Global Data --------------------------*/
OutputPluginListNode *outputPlugins = NULL;
@@ -53,6 +54,7 @@
OpAlertCSV_Init();
OpAlertSyslog2_Init();
OpAlertConsole_Init();
+ OpStreamStatCSV_Init();
return;
}
--- ../../../barnyard-0.2.0/src/output-plugins/op_stream_stat_csv.c Thu Jan 1 00:00:00 1970
+++ op_stream_stat_csv.c Wed Jul 14 21:42:18 2004
@@ -0,0 +1,388 @@
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <errno.h>
+
+#include "strlcpyu.h"
+#include "ConfigFile.h"
+#include "plugbase.h"
+#include "op_plugbase.h"
+#include "mstring.h"
+#include "util.h"
+#include "sid.h"
+#include "classification.h"
+#include "input-plugins/dp_stream_stat.h"
+#include "barnyard.h"
+
+
+/* KEYWORD DEFINES */
+#define CSV_START_TIME 1
+#define CSV_END_TIME 2
+#define CSV_CLIENT_BYTES 3
+#define CSV_SERVER_BYTES 4
+#define CSV_CLIENT_IP 5
+#define CSV_SERVER_IP 6
+#define CSV_CLIENT_PORT 7
+#define CSV_SERVER_PORT 8
+#define CSV_SERVER_PACKETS 9
+#define CSV_CLIENT_PACKETS 10
+
+/* D A T A S T R U C T U R E S **************************************/
+typedef struct _AlertCSVOpData
+{
+ char *filepath;
+ FILE *file;
+ int num_entries;
+ u_int32_t *entry_defs;
+} StreamStatCSVOpData;
+
+
+/* P R O T O T Y P E S ************************************************/
+static int OpStreamStatCSV_Setup(OutputPlugin *, char *args);
+static int OpStreamStatCSV_Exit(OutputPlugin *);
+static int OpStreamStatCSV_Start(OutputPlugin *, void *);
+static int OpStreamStatCSV_Stop(OutputPlugin *);
+static int OpStreamStatCSV(void *, void *);
+static int OpStreamStatCSV_LogConfig(OutputPlugin *);
+
+static StreamStatCSVOpData *StreamStatCSVOpParseArgs(char *);
+static void StreamStatCSVOpParseCustomFormat(StreamStatCSVOpData *data, char *format);
+static char *CSVEscape(char *);
+
+/* init routine makes this processor available for dataprocessor directives */
+void OpStreamStatCSV_Init()
+{
+ OutputPlugin *outputPlugin;
+
+ /*
+ * register the plugin name, its setup function, its type and the plugin
+ * information
+ */
+ outputPlugin = RegisterOutputPlugin("stream_stat_csv", "stream_stat");
+
+ outputPlugin->setupFunc = OpStreamStatCSV_Setup;
+ outputPlugin->exitFunc = OpStreamStatCSV_Exit;
+ outputPlugin->startFunc = OpStreamStatCSV_Start;
+ outputPlugin->stopFunc = OpStreamStatCSV_Stop;
+ outputPlugin->outputFunc = OpStreamStatCSV;
+ outputPlugin->logConfigFunc = OpStreamStatCSV_LogConfig;
+
+ /* tell people you're installed */
+ LogMessage("StreamStatCSV initialized\n");
+}
+
+static int OpStreamStatCSV_LogConfig ( OutputPlugin *outputPlugin)
+{
+
+ StreamStatCSVOpData *data = (StreamStatCSVOpData *)outputPlugin->data;
+
+ if (!outputPlugin || !outputPlugin->data)
+ return -1;
+
+ LogMessage("OpStreamStatCSV configured\n");
+ LogMessage(" Filepath: %s\n",data->filepath);
+ LogMessage(" Format: %s\n","");
+
+ return 0;
+}
+
+
+/* Setup the output plugin, process any arguments, link the functions to
+ * the output functional node
+ */
+static int OpStreamStatCSV_Setup(OutputPlugin *outputPlugin, char *args)
+{
+ /* setup the run time context for this output plugin */
+ outputPlugin->data = StreamStatCSVOpParseArgs(args);
+
+ return 0;
+}
+
+/* Inverse of the setup function, free memory allocated in Setup
+ * can't free the outputPlugin since it is also the list node itself
+ */
+static int OpStreamStatCSV_Exit(OutputPlugin *outputPlugin)
+{
+ StreamStatCSVOpData *data = (StreamStatCSVOpData *)outputPlugin->data;
+
+ if(data != NULL)
+ {
+ if(data->filepath != NULL)
+ free(data->filepath);
+ if(data->entry_defs != NULL)
+ free(data->entry_defs);
+ }
+
+ return 0;
+}
+
+/*
+ * this function gets called at start time, you should open any output files
+ * or establish DB connections, etc, here
+ */
+static int OpStreamStatCSV_Start(OutputPlugin *outputPlugin, void *spool_header)
+{
+ StreamStatCSVOpData *data = (StreamStatCSVOpData *)outputPlugin->data;
+
+ if(data == NULL)
+ FatalError("ERROR: Unable to find context for StreamStatCSV startup!\n");
+
+ /*if(pv.verbose >= 2) */
+ OpStreamStatCSV_LogConfig(outputPlugin);
+
+ /* Open file */
+ if((data->file = fopen(data->filepath, "a")) == NULL)
+ {
+ FatalError("ERROR: Unable to open '%s' (%s)\n", data->filepath,
+ strerror(errno));
+ }
+
+ OpStreamStatCSV_LogConfig(outputPlugin);
+ return 0;
+}
+
+static int OpStreamStatCSV_Stop(OutputPlugin *outputPlugin)
+{
+ StreamStatCSVOpData *data = (StreamStatCSVOpData *)outputPlugin->data;
+
+ if(data == NULL)
+ FatalError("ERROR: Unable to find context for StreamStatCSV startup!\n");
+
+ /* close file */
+ fclose(data->file);
+
+ return 0;
+}
+
+/*
+ * this is the primary output function for the plugin, this is what gets called
+ * for every record read
+ */
+static int OpStreamStatCSV(void *context, void *data)
+{
+ int i = 0;
+ Sid *sid = NULL;
+ ClassType *class_type = NULL;
+ char timestamp[TIMEBUF_SIZE];
+ StreamStatRecord *record = (StreamStatRecord *)data;
+ StreamStatCSVOpData *op_data = (StreamStatCSVOpData *)context;
+ char timestamp1[TIMEBUF_SIZE];
+ char timestamp2[TIMEBUF_SIZE];
+ FILE *file = op_data->file;
+ char *escaped_string;
+
+ if(op_data->num_entries == 0)
+ {
+ /* default output mode */
+ RenderTimestamp(record->start_time, timestamp1, TIMEBUF_SIZE);
+ RenderTimestamp(record->end_time, timestamp2, TIMEBUF_SIZE);
+ fprintf(op_data->file, "%s,%s,%u.%u.%u.%u,%u,%u.%u.%u.%u,%u,%u,%u,%u,%u\n",
+ timestamp1,
+ timestamp2,
+ (record->client_ip & 0x000000ff),
+ (record->client_ip & 0x0000ff00) >> 8,
+ (record->client_ip & 0x00ff0000) >> 16,
+ (record->client_ip & 0xff000000) >> 24,
+ record->client_port,
+ (record->server_ip & 0x000000ff),
+ (record->server_ip & 0x0000ff00) >> 8,
+ (record->server_ip & 0x00ff0000) >> 16,
+ (record->server_ip & 0xff000000) >> 24,
+ record->server_port,
+ record->server_bytes, record->server_packets,
+ record->client_bytes, record->client_packets);
+ }
+ for(i = 0; i < op_data->num_entries; ++i)
+ {
+ switch(op_data->entry_defs[i])
+ {
+ case CSV_START_TIME:
+ RenderTimestamp(record->start_time, timestamp1, TIMEBUF_SIZE);
+ fprintf(file, "%s", timestamp1);
+ break;
+ case CSV_END_TIME:
+ RenderTimestamp(record->start_time, timestamp1, TIMEBUF_SIZE);
+ fprintf(file, "%s", timestamp1);
+ break;
+ case CSV_CLIENT_BYTES:
+ fprintf(file, "%u", record->client_bytes);
+ break;
+ case CSV_SERVER_BYTES:
+ fprintf(file, "%u", record->server_bytes);
+ break;
+ case CSV_SERVER_IP:
+ fprintf(file, "%u.%u.%u.%u",
+ record->server_ip & 0x000000ff,
+ (record->server_ip & 0x0000ff00) >> 8,
+ (record->server_ip & 0x00ff0000) >> 16,
+ (record->server_ip & 0xff000000) >> 24);
+ break;
+ case CSV_CLIENT_IP:
+ fprintf(file, "%u.%u.%u.%u",
+ record->client_ip & 0x000000ff,
+ (record->client_ip & 0x0000ff00) >> 8,
+ (record->client_ip & 0x00ff0000) >> 16,
+ (record->client_ip & 0xff000000) >> 24);
+ break;
+ case CSV_SERVER_PORT:
+ fprintf(file, "%u", record->server_port);
+ break;
+ case CSV_CLIENT_PORT:
+ fprintf(file, "%u", record->client_port);
+ break;
+ case CSV_CLIENT_PACKETS:
+ fprintf(file, "%u", record->client_packets);
+ break;
+ case CSV_SERVER_PACKETS:
+ fprintf(file, "%u", record->server_packets);
+ break;
+ }
+ if(i < op_data->num_entries - 1)
+ fprintf(file, ",");
+ else
+ fprintf(file, "\n");
+ }
+ fflush(file);
+ return 0;
+}
+
+/* initialize the output processor for this particular instantiation */
+StreamStatCSVOpData *StreamStatCSVOpParseArgs(char *args)
+{
+ StreamStatCSVOpData *data;
+
+ data = (StreamStatCSVOpData *)SafeAlloc(sizeof(StreamStatCSVOpData));
+
+ if(args != NULL)
+ {
+ char **toks;
+ int num_toks;
+ /* parse out your args */
+ toks = mSplit(args, " ", 2, &num_toks, 0);
+ switch(num_toks)
+ {
+ case 2:
+ StreamStatCSVOpParseCustomFormat(data, toks[1]);
+ case 1:
+ data->filepath = strdup(toks[0]);
+ break;
+ case 0:
+ data->filepath = strdup("stats-csv.out");
+ break;
+ default:
+ FatalError("ERROR %s (%d) => Invalid arguments for StreamStatCSV "
+ "plugin: %s\n", file_name, file_line, args);
+ }
+ /* free your mSplit tokens */
+ FreeToks(toks, num_toks);
+ }
+ else
+ {
+ data->filepath = strdup("stats-csv.out");
+ }
+
+ return data;
+}
+
+
+void StreamStatCSVOpParseCustomFormat(StreamStatCSVOpData *data, char *format)
+{
+ char **toks;
+ int num_toks;
+ int i;
+ toks = mSplit(format, ",", 128, &num_toks, 0);
+ data->num_entries = num_toks;
+ data->entry_defs = (u_int32_t *)calloc(num_toks, sizeof(u_int32_t));
+ for(i = 0; i < num_toks; ++i)
+ {
+ if(strcasecmp("start_time", toks[i]) == 0)
+ {
+ data->entry_defs[i] = CSV_START_TIME;
+ }
+ else if(strcasecmp("end_time", toks[i]) == 0)
+ {
+ data->entry_defs[i] = CSV_END_TIME;
+ }
+ else if(strcasecmp("client_ip", toks[i]) == 0)
+ {
+ data->entry_defs[i] = CSV_CLIENT_IP;
+ }
+ else if(strcasecmp("client_port", toks[i]) == 0)
+ {
+ data->entry_defs[i] = CSV_CLIENT_PORT;
+ }
+ else if(strcasecmp("server_ip", toks[i]) == 0)
+ {
+ data->entry_defs[i] = CSV_SERVER_IP;
+ }
+ else if(strcasecmp("server_port", toks[i]) == 0)
+ {
+ data->entry_defs[i] = CSV_SERVER_PORT;
+ }
+ else if(strcasecmp("client_bytes", toks[i]) == 0)
+ {
+ data->entry_defs[i] = CSV_CLIENT_BYTES;
+ }
+ else if(strcasecmp("client_packets", toks[i]) == 0)
+ {
+ data->entry_defs[i] = CSV_CLIENT_PACKETS;
+ }
+ else if(strcasecmp("server_packets", toks[i]) == 0)
+ {
+ data->entry_defs[i] = CSV_SERVER_PACKETS;
+ }
+ else if(strcasecmp("server_bytes", toks[i]) == 0)
+ {
+ data->entry_defs[i] = CSV_SERVER_BYTES;
+ }
+ else
+ {
+ fprintf(stderr, "WARNING %s (%u) => Unrecognized keyword in "
+ "StreamStatCSV: %s\n", file_name, file_line, toks[i]);
+ }
+ }
+ FreeToks(toks, num_toks);
+}
+
+char *CSVEscape(char *input)
+{
+ size_t strLen;
+ char *buffer;
+ char *current;
+ if((strchr(input, ',') == NULL) && (strchr(input, '"') == NULL))
+ return strdup(input);
+ /* max size of escaped string is 2*size + 3, so we allocate that much */
+ strLen = strlen(input);
+ buffer = (char *)SafeAlloc((strLen * 2) + 3);
+ current = buffer;
+ *current = '"';
+ ++current;
+ while(*input != '\0')
+ {
+ switch(*input)
+ {
+ case '"':
+ *current = '\\';
+ ++current;
+ *current = '"';
+ ++current;
+ break;
+ case '\\':
+ *current = '\\';
+ ++current;
+ *current = '\\';
+ ++current;
+ break;
+ default:
+ *current = *input;
+ ++current;
+ break;
+ }
+ ++input;
+ }
+ *current = '"';
+ return buffer;
+}
Current thread:
- Re: RE: Network Behaviour Anomoly Detection Lawrence Reed (Oct 13)
