Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

spo_csv.c

Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
00003 ** Copyright (C) 2001 Brian Caswell <bmc@mitre.org>
00004 **
00005 ** This program is free software; you can redistribute it and/or modify
00006 ** it under the terms of the GNU General Public License as published by
00007 ** the Free Software Foundation; either version 2 of the License, or
00008 ** (at your option) any later version.
00009 **
00010 ** This program is distributed in the hope that it will be useful,
00011 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 ** GNU General Public License for more details.
00014 **
00015 ** You should have received a copy of the GNU General Public License
00016 ** along with this program; if not, write to the Free Software
00017 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00018 */
00019 
00020 /* $Id$ */
00021 
00022 /* spo_csv
00023  * 
00024  * Purpose:  output plugin for full alerting
00025  *
00026  * Arguments:  alert file (eventually)
00027  *   
00028  * Effect:
00029  *
00030  * Alerts are written to a file in the snort full alert format
00031  *
00032  * Comments:   Allows use of full alerts with other output plugin types
00033  *
00034  */
00035 
00036 #ifdef HAVE_CONFIG_H
00037 #include "config.h"
00038 #endif
00039 
00040 #include <sys/types.h>
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #ifndef WIN32
00044 #include <sys/socket.h>
00045 #include <netinet/in.h>
00046 #include <arpa/inet.h>
00047 #endif /* !WIN32 */
00048 
00049 #ifdef HAVE_STRINGS_H
00050 #include <strings.h>
00051 #endif
00052 
00053 #include "event.h"
00054 #include "decode.h"
00055 #include "plugbase.h"
00056 #include "spo_plugbase.h"
00057 #include "parser.h"
00058 #include "debug.h"
00059 #include "mstring.h"
00060 #include "util.h"
00061 #include "log.h"
00062 
00063 #include "snort.h"
00064 
00065 #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"
00066 
00067 typedef struct _AlertCSVConfig
00068 {
00069     char *type;
00070     struct _AlertCSVConfig *next;
00071 } AlertCSVConfig;
00072 
00073 typedef struct _AlertCSVData
00074 {
00075     FILE *file;
00076     char * csvargs;
00077     char ** args;
00078     int numargs;
00079     AlertCSVConfig *config;
00080 } AlertCSVData;
00081 
00082 
00083 /* list of function prototypes for this preprocessor */
00084 void AlertCSVInit(u_char *);
00085 AlertCSVData *AlertCSVParseArgs(char *);
00086 void AlertCSV(Packet *, char *, void *, Event *);
00087 void AlertCSVCleanExit(int, void *);
00088 void AlertCSVRestart(int, void *);
00089 void RealAlertCSV(Packet * p, char *msg, FILE * file, char **args, 
00090         int numargs, Event *event);
00091 static char *CSVEscape(char *input);
00092 
00093 /*
00094  * Function: SetupCSV()
00095  *
00096  * Purpose: Registers the output plugin keyword and initialization 
00097  *          function into the output plugin list.  This is the function that
00098  *          gets called from InitOutputPlugins() in plugbase.c.
00099  *
00100  * Arguments: None.
00101  *
00102  * Returns: void function
00103  *
00104  */
00105 void AlertCSVSetup(void)
00106 {
00107     /* link the preprocessor keyword to the init function in 
00108        the preproc list */
00109     RegisterOutputPlugin("alert_CSV", NT_OUTPUT_ALERT, AlertCSVInit);
00110 
00111     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Output plugin: alert_CSV is setup...\n"););
00112 }
00113 
00114 
00115 /*
00116  * Function: CSVInit(u_char *)
00117  *
00118  * Purpose: Calls the argument parsing function, performs final setup on data
00119  *          structs, links the preproc function into the function list.
00120  *
00121  * Arguments: args => ptr to argument string
00122  *
00123  * Returns: void function
00124  *
00125  */
00126 void AlertCSVInit(u_char *args)
00127 {
00128     AlertCSVData *data;
00129     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Output: CSV Initialized\n"););
00130 
00131     pv.alert_plugin_active = 1;
00132 
00133     /* parse the argument list from the rules file */
00134     data = AlertCSVParseArgs(args);
00135 
00136     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Linking CSV functions to call lists...\n"););
00137 
00138     /* Set the preprocessor function into the function list */
00139     AddFuncToOutputList(AlertCSV, NT_OUTPUT_ALERT, data);
00140     AddFuncToCleanExitList(AlertCSVCleanExit, data);
00141     AddFuncToRestartList(AlertCSVRestart, data);
00142 }
00143 
00144 /*
00145  * Function: ParseCSVArgs(char *)
00146  *
00147  * Purpose: Process the preprocessor arguements from the rules file and 
00148  *          initialize the preprocessor's data struct.  This function doesn't
00149  *          have to exist if it makes sense to parse the args in the init 
00150  *          function.
00151  *
00152  * Arguments: args => argument list
00153  *
00154  * Returns: void function
00155  *
00156  */
00157 AlertCSVData *AlertCSVParseArgs(char *args)
00158 {
00159     char **toks;
00160     int num_toks; 
00161     char *filename;
00162     AlertCSVData *data;
00163     /*    SpoCSVConfig *config; */
00164     int num;
00165 
00166     data = (AlertCSVData *)SnortAlloc(sizeof(AlertCSVData));
00167     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "ParseCSVArgs: %s\n", args););
00168 
00169     toks = mSplit(args, " ", 2, &num_toks, 0);
00170 
00171     if(num_toks <= 1)
00172     {
00173         FatalError("You must supply at least TWO arguments for "
00174                    "the CSV plugin...\n"
00175                    "\t ... arguements of \"/path/to/output/file default\" "
00176                    "as a minimum.\n");
00177     }
00178  
00179     filename = ProcessFileOption(toks[0]);
00180     data->file = OpenAlertFile(filename);
00181     free(filename);
00182     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"AlertCSV Got filename\n"););
00183 
00184     if(!strncasecmp("default", toks[1], 7))
00185     {
00186             data->csvargs = DEFAULT_CSV;
00187     }
00188     else
00189     {
00190             data->csvargs = toks[1]; 
00191     } 
00192 
00193     DEBUG_WRAP(DebugMessage(DEBUG_LOG,"AlertCSV Got Config ARGS\n"););
00194     
00195     toks = mSplit(data->csvargs, ",", 128, &num_toks, 0);
00196 
00197     num = num_toks;
00198     data->args = toks;
00199     data->numargs = num;
00200 
00201     return data;
00202 }
00203 
00204 void AlertCSVCleanExit(int signal, void *arg)
00205 {
00206     AlertCSVData *data = (AlertCSVData *)arg;
00207     /* close alert file */
00208     DEBUG_WRAP(DebugMessage(DEBUG_LOG,"CSVCleanExitFunc\n"););
00209     fclose(data->file);
00210     /* free memory from SpoCSVData */
00211     free(data);
00212 }
00213 
00214 void AlertCSVRestart(int signal, void *arg)
00215 {
00216     AlertCSVData *data = (AlertCSVData *)arg;
00217     /* close alert file */
00218     DEBUG_WRAP(DebugMessage(DEBUG_LOG,"CSVRestartFunc\n"););
00219     fclose(data->file);
00220     /* free memory from SpoCSVData */
00221     free(data);
00222 }
00223 
00224 
00225 void AlertCSV(Packet *p, char *msg, void *arg, Event *event)
00226 {
00227     AlertCSVData *data = (AlertCSVData *)arg;
00228     RealAlertCSV(p, msg, data->file, data->args, data->numargs, event); 
00229     return;
00230 }
00231 
00232 
00233 
00234 /*
00235  *
00236  * Function: AlertCSV(Packet *, char *, FILE *, char *, numargs const int)
00237  *
00238  * Purpose: Write a user defined CSV message
00239  *
00240  * Arguments:     p => packet. (could be NULL)
00241  *              msg => the message to send
00242  *             file => file pointer to print data to
00243  *             args => CSV output arguements 
00244  *          numargs => number of arguements
00245  * Returns: void function
00246  *
00247  */
00248 void RealAlertCSV(Packet * p, char *msg, FILE * file, char **args, 
00249         int numargs, Event *event)
00250 {
00251     char timestamp[TIMEBUF_SIZE];
00252     int num; 
00253     char *type;
00254     char tcpFlags[9];
00255 
00256     if(p == NULL)
00257         return;
00258 
00259     bzero((char *) timestamp, TIMEBUF_SIZE);
00260     ts_print(p == NULL ? NULL : (struct timeval *) & p->pkth->ts, timestamp);
00261 
00262     DEBUG_WRAP(DebugMessage(DEBUG_LOG,"Logging CSV Alert data\n");); 
00263 
00264     for (num = 0; num < numargs; num++)
00265     {
00266         type = args[num];
00267 
00268         DEBUG_WRAP(DebugMessage(DEBUG_LOG, "CSV Got type %s %d\n", type, num);); 
00269 
00270         if(!strncasecmp("timestamp", type, 9))
00271         {
00272             fwrite(timestamp, strlen(timestamp), 1, file);
00273         }
00274         else if(!strncasecmp("sig_generator",type,13))
00275         {
00276            if(event != NULL)
00277            {
00278                fprintf(file, "%lu",  (unsigned long) event->sig_generator);
00279            }
00280         }
00281         else if(!strncasecmp("sig_id",type,6))
00282         {
00283            if(event != NULL)
00284            {
00285               fprintf(file, "%lu",  (unsigned long) event->sig_id);
00286            }
00287         }
00288         else if(!strncasecmp("sig_rev",type,7))
00289         {
00290            if(event != NULL)
00291            {
00292               fprintf(file, "%lu",  (unsigned long) event->sig_rev);
00293            }
00294         }
00295         else if(!strncasecmp("msg", type, 3))
00296         {
00297         /* Escape the msg */
00298         char *escaped_msg;
00299         if(!(escaped_msg = CSVEscape(msg)))
00300         {
00301             FatalError("Out of memory escaping msg string");
00302         }
00303             fwrite(escaped_msg, strlen(escaped_msg),1,file);
00304         free(escaped_msg);
00305         }
00306         else if(!strncasecmp("proto", type, 5))
00307         {
00308         if(p->iph)
00309         {
00310             switch (p->iph->ip_proto)
00311             {
00312                 case IPPROTO_UDP:
00313                     fwrite("UDP", 3,1,file);
00314                     break;
00315                 case IPPROTO_TCP:
00316                     fwrite("TCP", 3,1,file);
00317                     break;
00318                 case IPPROTO_ICMP:
00319                     fwrite("ICMP", 4,1,file);
00320                     break;
00321             }
00322         }
00323         }
00324         else if(!strncasecmp("ethsrc", type, 6))
00325         {
00326             if(p->eh)
00327             {
00328             fprintf(file, "%X:%X:%X:%X:%X:%X", p->eh->ether_src[0],
00329             p->eh->ether_src[1], p->eh->ether_src[2], p->eh->ether_src[3],
00330             p->eh->ether_src[4], p->eh->ether_src[5]);
00331             }
00332         } 
00333         else if(!strncasecmp("ethdst", type, 6))
00334         {
00335             if(p->eh)
00336             {
00337             fprintf(file, "%X:%X:%X:%X:%X:%X", p->eh->ether_dst[0],
00338             p->eh->ether_dst[1], p->eh->ether_dst[2], p->eh->ether_dst[3],
00339             p->eh->ether_dst[4], p->eh->ether_dst[5]);
00340             }
00341         }
00342         else if(!strncasecmp("ethtype", type, 7))
00343         {
00344             if(p->eh)
00345             {
00346             fprintf(file,"0x%X",ntohs(p->eh->ether_type));
00347             }
00348         }
00349         else if(!strncasecmp("udplength", type, 9))
00350         {
00351             if(p->udph)
00352                 fprintf(file,"%d",ntohs(p->udph->uh_len));
00353         }
00354         else if(!strncasecmp("ethlen", type, 6))
00355         {
00356             if(p->eh)
00357             fprintf(file,"0x%X",p->pkth->len);
00358         }
00359         else if(!strncasecmp("trheader", type, 8))
00360         {
00361             if(p->trh)
00362             PrintTrHeader(file, p);
00363         }
00364         else if(!strncasecmp("srcport", type, 7))
00365         {
00366         if(p->iph)
00367         {
00368                 switch(p->iph->ip_proto)
00369                 {
00370                     case IPPROTO_UDP:
00371                     case IPPROTO_TCP:
00372                             fprintf(file, "%d", p->sp);
00373                             break;
00374                 }    
00375         }
00376         }
00377         else if(!strncasecmp("dstport", type, 7))
00378         {
00379         if(p->iph)
00380         {
00381                 switch(p->iph->ip_proto)
00382                 {
00383                     case IPPROTO_UDP:
00384                     case IPPROTO_TCP:
00385                             fprintf(file, "%d", p->dp);
00386                             break;
00387                 }    
00388         }
00389         }
00390         else if(!strncasecmp("src", type, 3))
00391         {
00392         if(p->iph)
00393             fputs(inet_ntoa(p->iph->ip_src), file);
00394         }
00395         else if(!strncasecmp("dst", type, 3))
00396         {
00397         if(p->iph)
00398             fputs(inet_ntoa(p->iph->ip_dst), file); 
00399         }
00400         else if(!strncasecmp("icmptype",type,8))
00401         {
00402             if(p->icmph)
00403             {
00404                 fprintf(file,"%d",p->icmph->type);
00405             }
00406         }
00407         else if(!strncasecmp("icmpcode",type,8))
00408         {
00409             if(p->icmph)
00410             {
00411                 fprintf(file,"%d",p->icmph->code);
00412             }
00413         }
00414         else if(!strncasecmp("icmpid",type,6))
00415         {
00416             if(p->icmph)
00417             fprintf(file,"%d",ntohs(p->icmph->s_icmp_id));         
00418         }
00419         else if(!strncasecmp("icmpseq",type,7))
00420         {
00421             if(p->icmph)
00422                     fprintf(file,"%d",ntohs(p->icmph->s_icmp_seq));
00423         }
00424         else if(!strncasecmp("ttl",type,3))
00425         {
00426             if(p->iph)
00427                 fprintf(file,"%d",p->iph->ip_ttl);
00428         }
00429         else if(!strncasecmp("tos",type,3))
00430         {
00431             if(p->iph)
00432                 fprintf(file,"%d",p->iph->ip_tos);
00433         }
00434         else if(!strncasecmp("id",type,2))
00435         {
00436             if(p->iph)
00437                 fprintf(file,"%d",ntohs(p->iph->ip_id));
00438         }
00439         else if(!strncasecmp("iplen",type,5))
00440         {
00441             if(p->iph)
00442                 fprintf(file,"%d",IP_HLEN(p->iph) << 2);
00443         }
00444         else if(!strncasecmp("dgmlen",type,6))
00445         {
00446             if(p->iph)
00447                 fprintf(file,"%d",ntohs(p->iph->ip_len));
00448         }
00449         else if(!strncasecmp("tcpseq",type,6))
00450         {
00451             if(p->tcph)
00452                 fprintf(file,"0x%lX",(u_long) ntohl(p->tcph->th_seq));
00453         }
00454         else if(!strncasecmp("tcpack",type,6))
00455         {
00456             if(p->tcph)
00457                 fprintf(file,"0x%lX",(u_long) ntohl(p->tcph->th_ack));
00458         }
00459         else if(!strncasecmp("tcplen",type,6))
00460         {
00461             if(p->tcph)
00462                 fprintf(file,"%d",TCP_OFFSET(p->tcph) << 2);
00463         }
00464         else if(!strncasecmp("tcpwindow",type,9))
00465         {
00466             if(p->tcph)
00467                 fprintf(file,"0x%X",ntohs(p->tcph->th_win));
00468         }
00469         else if(!strncasecmp("tcpflags",type,8))
00470         {
00471             if(p->tcph)
00472             {   
00473                 CreateTCPFlagString(p, tcpFlags);
00474                 fprintf(file,"%s", tcpFlags);
00475             }
00476         }
00477 
00478         if (num < numargs - 1) 
00479             fwrite(",",1,1,file);
00480     }
00481     fputc('\n', file);
00482    
00483 
00484     return;
00485 }
00486 
00487 
00488 char *CSVEscape(char *input)
00489 {
00490     size_t strLen;
00491     char *buffer;
00492     char *current;
00493     if((strchr(input, ',') == NULL) && (strchr(input, '"') == NULL))
00494         return strdup(input);
00495     /* max size of escaped string is 2*size + 3, so we allocate that much */
00496     strLen = strlen(input);
00497     buffer = (char *)SnortAlloc((strLen * 2) + 3);
00498     current = buffer;
00499     *current = '"';
00500     ++current;
00501     while(*input != '\0')
00502     {
00503         switch(*input)
00504         {
00505             case '"':
00506                 *current = '\\';
00507                 ++current;
00508                 *current = '"';
00509                 ++current;
00510                 break;
00511             case '\\':
00512                 *current = '\\';
00513                 ++current;
00514                 *current = '\\';
00515                 ++current;
00516                 break;
00517             default:
00518                 *current = *input;
00519                 ++current;
00520                 break;
00521         }
00522         ++input;
00523     }
00524     *current = '"';
00525     return buffer;
00526 }
00527 

Generated on Sun May 14 14:51:14 2006 by  doxygen 1.4.2