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)