Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

546 lines (490 sloc) 15.566 kb
/*
** Copyright (C) 2002-2009 Sourcefire, Inc.
** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
** Copyright (C) 2001 Brian Caswell <bmc@mitre.org>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License Version 2 as
** published by the Free Software Foundation. You may not use, modify or
** distribute this program under any other version of the GNU General
** Public License.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* $Id$ */
/* spo_csv
*
* Purpose: output plugin for csv alerting
*
* Arguments: alert file (eventually)
*
* Effect:
*
* Alerts are written to a file in the snort csv alert format
*
* Comments: Allows use of csv alerts with other output plugin types
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif /* !WIN32 */
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include "decode.h"
#include "plugbase.h"
#include "parser.h"
#include "debug.h"
#include "mstring.h"
#include "util.h"
#include "log.h"
#include "map.h"
#include "unified2.h"
#include "barnyard2.h"
#include "sfutil/sf_textlog.h"
#include "log_text.h"
#include "ipv6_port.h"
#define DEFAULT_CSV "timestamp,sig_generator,sig_id,sig_rev,msg,proto,src,srcport,dst,dstport,ethsrc,ethdst,ethlen,tcpflags,tcpseq,tcpack,tcpln,tcpwindow,ttl,tos,id,dgmlen,iplen,icmptype,icmpcode,icmpid,icmpseq"
#define DEFAULT_FILE "alert.csv"
#define DEFAULT_LIMIT (128*M_BYTES)
#define LOG_BUFFER (4*K_BYTES)
typedef struct _AlertCSVConfig
{
char *type;
struct _AlertCSVConfig *next;
} AlertCSVConfig;
typedef struct _AlertCSVData
{
TextLog* log;
char * csvargs;
char ** args;
int numargs;
AlertCSVConfig *config;
} AlertCSVData;
/* list of function prototypes for this preprocessor */
static void AlertCSVInit(char *);
static AlertCSVData *AlertCSVParseArgs(char *);
static void AlertCSV(Packet *, void *, uint32_t, void *);
static void AlertCSVCleanExit(int, void *);
static void AlertCSVRestart(int, void *);
static void RealAlertCSV(
Packet*, void*, uint32_t, char **args, int numargs, TextLog*
);
/*
* Function: SetupCSV()
*
* Purpose: Registers the output plugin keyword and initialization
* function into the output plugin list. This is the function that
* gets called from InitOutputPlugins() in plugbase.c.
*
* Arguments: None.
*
* Returns: void function
*
*/
void AlertCSVSetup(void)
{
/* link the preprocessor keyword to the init function in
the preproc list */
RegisterOutputPlugin("alert_csv", OUTPUT_TYPE_FLAG__ALERT, AlertCSVInit);
DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Output plugin: alert_csv is setup...\n"););
}
/*
* Function: CSVInit(char *)
*
* Purpose: Calls the argument parsing function, performs final setup on data
* structs, links the preproc function into the function list.
*
* Arguments: args => ptr to argument string
*
* Returns: void function
*
*/
static void AlertCSVInit(char *args)
{
AlertCSVData *data;
DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Output: CSV Initialized\n"););
/* parse the argument list from the rules file */
data = AlertCSVParseArgs(args);
DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Linking CSV functions to call lists...\n"););
/* Set the preprocessor function into the function list */
AddFuncToOutputList(AlertCSV, OUTPUT_TYPE__ALERT, data);
AddFuncToCleanExitList(AlertCSVCleanExit, data);
AddFuncToRestartList(AlertCSVRestart, data);
}
/*
* Function: ParseCSVArgs(char *)
*
* Purpose: Process positional args, if any. Syntax is:
* output alert_csv: [<logpath> ["default"|<list> [<limit>]]]
* list ::= <field>(,<field>)*
* field ::= "dst"|"src"|"ttl" ...
* limit ::= <number>('G'|'M'|K')
*
* Arguments: args => argument list
*
* Returns: void function
*/
static AlertCSVData *AlertCSVParseArgs(char *args)
{
char **toks;
int num_toks;
AlertCSVData *data;
char* filename = NULL;
unsigned long limit = DEFAULT_LIMIT;
int i;
DEBUG_WRAP(DebugMessage(DEBUG_INIT, "ParseCSVArgs: %s\n", args););
data = (AlertCSVData *)SnortAlloc(sizeof(AlertCSVData));
if ( !data )
{
FatalError("alert_csv: unable to allocate memory!\n");
}
if ( !args ) args = "";
toks = mSplit((char *)args, " \t", 4, &num_toks, '\\');
for (i = 0; i < num_toks; i++)
{
const char* tok = toks[i];
char *end;
switch (i)
{
case 0:
if ( !strcasecmp(tok, "stdout") )
filename = SnortStrdup(tok);
else
filename = ProcessFileOption(barnyard2_conf_for_parsing, tok);
break;
case 1:
if ( !strcasecmp("default", tok) )
{
data->csvargs = strdup(DEFAULT_CSV);
}
else
{
data->csvargs = strdup(toks[1]);
}
break;
case 2:
limit = strtol(tok, &end, 10);
if ( tok == end )
FatalError("alert_csv error in %s(%i): %s\n",
file_name, file_line, tok);
if ( end && toupper(*end) == 'G' )
limit <<= 30; /* GB */
else if ( end && toupper(*end) == 'M' )
limit <<= 20; /* MB */
else if ( end && toupper(*end) == 'K' )
limit <<= 10; /* KB */
break;
case 3:
FatalError("alert_csv: error in %s(%i): %s\n",
file_name, file_line, tok);
break;
}
}
if ( !data->csvargs ) data->csvargs = strdup(DEFAULT_CSV);
if ( !filename ) filename = ProcessFileOption(barnyard2_conf_for_parsing, DEFAULT_FILE);
mSplitFree(&toks, num_toks);
toks = mSplit(data->csvargs, ",", 128, &num_toks, 0);
data->args = toks;
data->numargs = num_toks;
DEBUG_WRAP(DebugMessage(
DEBUG_INIT, "alert_csv: '%s' '%s' %ld\n", filename, data->csvargs, limit
););
data->log = TextLog_Init(filename, LOG_BUFFER, limit);
if ( filename ) free(filename);
return data;
}
static void AlertCSVCleanup(int signal, void *arg, const char* msg)
{
AlertCSVData *data = (AlertCSVData *)arg;
/* close alert file */
DEBUG_WRAP(DebugMessage(DEBUG_LOG,"%s\n", msg););
if(data)
{
mSplitFree(&data->args, data->numargs);
if (data->log) TextLog_Term(data->log);
free(data->csvargs);
/* free memory from SpoCSVData */
free(data);
}
}
static void AlertCSVCleanExit(int signal, void *arg)
{
AlertCSVCleanup(signal, arg, "AlertCSVCleanExit");
}
static void AlertCSVRestart(int signal, void *arg)
{
AlertCSVCleanup(signal, arg, "AlertCSVRestart");
}
static void AlertCSV(Packet *p, void *event, uint32_t event_type, void *arg)
{
AlertCSVData *data = (AlertCSVData *)arg;
RealAlertCSV(p, event, event_type, data->args, data->numargs, data->log);
}
/*
*
* Function: RealAlertCSV(Packet *, char *, FILE *, char *, numargs const int)
*
* Purpose: Write a user defined CSV message
*
* Arguments: p => packet. (could be NULL)
* msg => the message to send
* args => CSV output arguements
* numargs => number of arguements
* log => Log
* Returns: void function
*
*/
static void RealAlertCSV(Packet * p, void *event, uint32_t event_type,
char **args, int numargs, TextLog* log)
{
int num;
SigNode *sn;
char *type;
char tcpFlags[9];
if(p == NULL)
return;
DEBUG_WRAP(DebugMessage(DEBUG_LOG,"Logging CSV Alert data\n"););
for (num = 0; num < numargs; num++)
{
type = args[num];
DEBUG_WRAP(DebugMessage(DEBUG_LOG, "CSV Got type %s %d\n", type, num););
if(!strncasecmp("timestamp", type, 9))
{
LogTimeStamp(log, p);
}
else if(!strncasecmp("sig_generator",type,13))
{
if(event != NULL)
{
TextLog_Print(log, "%lu",
(unsigned long) ntohl(((Unified2EventCommon *)event)->generator_id));
}
}
else if(!strncasecmp("sig_id",type,6))
{
if(event != NULL)
{
TextLog_Print(log, "%lu",
(unsigned long) ntohl(((Unified2EventCommon *)event)->signature_id));
}
}
else if(!strncasecmp("sig_rev",type,7))
{
if(event != NULL)
{
TextLog_Print(log, "%lu",
(unsigned long) ntohl(((Unified2EventCommon *)event)->signature_revision));
}
}
else if(!strncasecmp("msg", type, 3))
{
if ( event != NULL )
{
sn = GetSigByGidSid(ntohl(((Unified2EventCommon *)event)->generator_id),
ntohl(((Unified2EventCommon *)event)->signature_id));
if (sn != NULL)
{
if ( !TextLog_Quote(log, sn->msg) )
{
FatalError("Not enough buffer space to escape msg string\n");
}
}
}
}
else if(!strncasecmp("proto", type, 5))
{
if(IPH_IS_VALID(p))
{
switch (GET_IPH_PROTO(p))
{
case IPPROTO_UDP:
TextLog_Puts(log, "UDP");
break;
case IPPROTO_TCP:
TextLog_Puts(log, "TCP");
break;
case IPPROTO_ICMP:
TextLog_Puts(log, "ICMP");
break;
}
}
}
else if(!strncasecmp("ethsrc", type, 6))
{
if(p->eh)
{
TextLog_Print(log, "%X:%X:%X:%X:%X:%X", p->eh->ether_src[0],
p->eh->ether_src[1], p->eh->ether_src[2], p->eh->ether_src[3],
p->eh->ether_src[4], p->eh->ether_src[5]);
}
}
else if(!strncasecmp("ethdst", type, 6))
{
if(p->eh)
{
TextLog_Print(log, "%X:%X:%X:%X:%X:%X", p->eh->ether_dst[0],
p->eh->ether_dst[1], p->eh->ether_dst[2], p->eh->ether_dst[3],
p->eh->ether_dst[4], p->eh->ether_dst[5]);
}
}
else if(!strncasecmp("ethtype", type, 7))
{
if(p->eh)
{
TextLog_Print(log, "0x%X",ntohs(p->eh->ether_type));
}
}
else if(!strncasecmp("udplength", type, 9))
{
if(p->udph)
TextLog_Print(log, "%d",ntohs(p->udph->uh_len));
}
else if(!strncasecmp("ethlen", type, 6))
{
if(p->eh)
TextLog_Print(log, "0x%X",p->pkth->len);
}
#ifndef NO_NON_ETHER_DECODER
else if(!strncasecmp("trheader", type, 8))
{
if(p->trh)
LogTrHeader(log, p);
}
#endif
else if(!strncasecmp("srcport", type, 7))
{
if(IPH_IS_VALID(p))
{
switch(GET_IPH_PROTO(p))
{
case IPPROTO_UDP:
case IPPROTO_TCP:
TextLog_Print(log, "%d", p->sp);
break;
}
}
}
else if(!strncasecmp("dstport", type, 7))
{
if(IPH_IS_VALID(p))
{
switch(GET_IPH_PROTO(p))
{
case IPPROTO_UDP:
case IPPROTO_TCP:
TextLog_Print(log, "%d", p->dp);
break;
}
}
}
else if(!strncasecmp("src", type, 3))
{
if(IPH_IS_VALID(p))
TextLog_Puts(log, inet_ntoa(GET_SRC_ADDR(p)));
}
else if(!strncasecmp("dst", type, 3))
{
if(IPH_IS_VALID(p))
TextLog_Puts(log, inet_ntoa(GET_DST_ADDR(p)));
}
else if(!strncasecmp("icmptype",type,8))
{
if(p->icmph)
{
TextLog_Print(log, "%d",p->icmph->type);
}
}
else if(!strncasecmp("icmpcode",type,8))
{
if(p->icmph)
{
TextLog_Print(log, "%d",p->icmph->code);
}
}
else if(!strncasecmp("icmpid",type,6))
{
if(p->icmph)
TextLog_Print(log, "%d",ntohs(p->icmph->s_icmp_id));
}
else if(!strncasecmp("icmpseq",type,7))
{
if(p->icmph)
TextLog_Print(log, "%d",ntohs(p->icmph->s_icmp_seq));
}
else if(!strncasecmp("ttl",type,3))
{
if(IPH_IS_VALID(p))
TextLog_Print(log, "%d",GET_IPH_TTL(p));
}
else if(!strncasecmp("tos",type,3))
{
if(IPH_IS_VALID(p))
TextLog_Print(log, "%d",GET_IPH_TOS(p));
}
else if(!strncasecmp("id",type,2))
{
if(IPH_IS_VALID(p))
TextLog_Print(log, "%u", IS_IP6(p) ? ntohl(GET_IPH_ID(p)) : ntohs((u_int16_t)GET_IPH_ID(p)));
}
else if(!strncasecmp("iplen",type,5))
{
if(IPH_IS_VALID(p))
TextLog_Print(log, "%d",GET_IPH_LEN(p) << 2);
}
else if(!strncasecmp("dgmlen",type,6))
{
if(IPH_IS_VALID(p))
// XXX might cause a bug when IPv6 is printed?
TextLog_Print(log, "%d",ntohs(GET_IPH_LEN(p)));
}
else if(!strncasecmp("tcpseq",type,6))
{
if(p->tcph)
TextLog_Print(log, "0x%lX",(u_long) ntohl(p->tcph->th_seq));
}
else if(!strncasecmp("tcpack",type,6))
{
if(p->tcph)
TextLog_Print(log, "0x%lX",(u_long) ntohl(p->tcph->th_ack));
}
else if(!strncasecmp("tcplen",type,6))
{
if(p->tcph)
TextLog_Print(log, "%d",TCP_OFFSET(p->tcph) << 2);
}
else if(!strncasecmp("tcpwindow",type,9))
{
if(p->tcph)
TextLog_Print(log, "0x%X",ntohs(p->tcph->th_win));
}
else if(!strncasecmp("tcpflags",type,8))
{
if(p->tcph)
{
CreateTCPFlagString(p, tcpFlags);
TextLog_Print(log, "%s", tcpFlags);
}
}
DEBUG_WRAP(DebugMessage(DEBUG_LOG, "WOOT!\n"););
if (num < numargs - 1)
TextLog_Putc(log, ',');
}
TextLog_NewLine(log);
TextLog_Flush(log);
}
Jump to Line
Something went wrong with that request. Please try again.