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

spo_alert_syslog.c

Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 /* $Id$ */
00019 
00020 /* spo_alert_syslog 
00021  * 
00022  * Purpose:
00023  *
00024  * This module sends alerts to the syslog service.
00025  *
00026  * Arguments:
00027  *   
00028  * Logging mechanism?
00029  *
00030  * Effect:
00031  *
00032  * Alerts are written to the syslog service with in the facility indicated by
00033  * the module arguments.
00034  *
00035  * Comments:
00036  *
00037  * First try
00038  *
00039  */
00040 
00041 #ifdef HAVE_CONFIG_H
00042 #include "config.h"
00043 #endif
00044 
00045 #include <sys/types.h>
00046 #include <syslog.h>
00047 #include <stdlib.h>
00048 #ifdef HAVE_STRINGS_H
00049 #include <strings.h>
00050 #endif
00051 
00052 #ifndef WIN32
00053 #include <sys/socket.h>
00054 #include <netinet/in.h>
00055 #include <arpa/inet.h>
00056 #endif /* !WIN32 */
00057 
00058 #include "decode.h"
00059 #include "event.h"
00060 #include "rules.h"
00061 #include "plugbase.h"
00062 #include "spo_plugbase.h"
00063 #include "debug.h"
00064 #include "parser.h"
00065 #include "mstring.h"
00066 #include "util.h"
00067 
00068 #include "snort.h"
00069 
00070 typedef struct _SyslogData
00071 {
00072     int facility;
00073     int priority;
00074     int options;
00075 } SyslogData;
00076 
00077 void AlertSyslogInit(u_char *);
00078 SyslogData *ParseSyslogArgs(char *);
00079 void AlertSyslog(Packet *, char *, void *, Event *);
00080 void AlertSyslogCleanExit(int, void *);
00081 void AlertSyslogRestart(int, void *);
00082 
00083 
00084 
00085 /*
00086  * Function: SetupSyslog()
00087  *
00088  * Purpose: Registers the output plugin keyword and initialization 
00089  *          function into the output plugin list.  This is the function that
00090  *          gets called from InitOutputPlugins() in plugbase.c.
00091  *
00092  * Arguments: None.
00093  *
00094  * Returns: void function
00095  *
00096  */
00097 void AlertSyslogSetup(void)
00098 {
00099     /* link the preprocessor keyword to the init function in 
00100        the preproc list */
00101     RegisterOutputPlugin("alert_syslog", NT_OUTPUT_ALERT, AlertSyslogInit);
00102     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"Output plugin: Alert-Syslog is setup...\n"););
00103 }
00104 
00105 
00106 /*
00107  * Function: AlertSyslogInit(u_char *)
00108  *
00109  * Purpose: Calls the argument parsing function, performs final setup on data
00110  *          structs, links the preproc function into the function list.
00111  *
00112  * Arguments: args => ptr to argument string
00113  *
00114  * Returns: void function
00115  *
00116  */
00117 void AlertSyslogInit(u_char *args)
00118 {
00119     SyslogData *data;
00120     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Output: Alert-Syslog Initialized\n"););
00121 
00122     pv.alert_plugin_active = 1;
00123 
00124     /* parse the argument list from the rules file */
00125     data = ParseSyslogArgs(args);
00126 
00127     if (pv.daemon_flag)
00128         data->options |= LOG_PID;
00129 
00130     openlog("snort", data->options, data->facility);
00131 
00132     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"Linking syslog alert function to call list...\n"););
00133 
00134     /* Set the preprocessor function into the function list */
00135     AddFuncToOutputList(AlertSyslog, NT_OUTPUT_ALERT, data);
00136     AddFuncToCleanExitList(AlertSyslogCleanExit, data);
00137     AddFuncToRestartList(AlertSyslogRestart, data);
00138 }
00139 
00140 
00141 
00142 /*
00143  * Function: ParseSyslogArgs(char *)
00144  *
00145  * Purpose: Process the preprocessor arguements from the rules file and 
00146  *          initialize the preprocessor's data struct.  This function doesn't
00147  *          have to exist if it makes sense to parse the args in the init 
00148  *          function.
00149  *
00150  * Arguments: args => argument list
00151  *
00152  * Returns: void function
00153  *
00154  */
00155 SyslogData *ParseSyslogArgs(char *args)
00156 {
00157 #ifdef WIN32
00158     char *DEFAULT_SYSLOG_HOST = "127.0.0.1";
00159     int   DEFAULT_SYSLOG_PORT = 514;
00160     char **config_toks;
00161     char **host_toks;
00162     char  *host_string = args;
00163     int num_config_toks, num_host_toks;
00164 #endif
00165     char **facility_toks;
00166     char  *facility_string = args;
00167     int num_facility_toks = 0;
00168     int i = 0;
00169     SyslogData *data;
00170     char *tmp;
00171 
00172     data = (SyslogData *)SnortAlloc(sizeof(SyslogData));
00173 
00174     /* default values for syslog output */
00175     data->options = 0;
00176     data->facility = LOG_AUTH;
00177     data->priority = LOG_INFO;
00178 
00179     if(args == NULL)
00180     {
00181         /* horrible kludge to catch default initialization */
00182         if(file_name != NULL)
00183         {            
00184             LogMessage("%s(%d) => No arguments to alert_syslog preprocessor!\n",
00185                     file_name, file_line);
00186         }
00187 
00188         return data;
00189 
00190     }
00191 
00192     /*
00193      * NON-WIN32:  Config should be in the format:
00194      *   output alert_syslog: LOG_AUTH LOG_ALERT
00195      * 
00196      * WIN32:  Config can be in any of these formats:
00197      *   output alert_syslog: LOG_AUTH LOG_ALERT
00198      *   output alert_syslog: host=hostname, LOG_AUTH LOG_ALERT
00199      *   output alert_syslog: host=hostname:port, LOG_AUTH LOG_ALERT
00200      */
00201 
00202 #ifdef WIN32
00203     /* split the host/port part from the facilities/priorities part */
00204     config_toks = mSplit(args, ",", 2, &num_config_toks, '\\');
00205     switch( num_config_toks )
00206     {
00207         case 1:  /* config consists of only facility/priority info */
00208             LogMessage("alert_syslog output processor is defaulting to syslog "
00209                     "server on %s port %d!\n",
00210                     DEFAULT_SYSLOG_HOST, DEFAULT_SYSLOG_PORT);
00211             strncpy(pv.syslog_server, DEFAULT_SYSLOG_HOST, STD_BUF-1);
00212             pv.syslog_server_port = DEFAULT_SYSLOG_PORT;
00213             facility_string = config_toks[0];
00214             break;
00215 
00216         case 2:  /* config consists of host info, and facility/priority info */
00217             host_string     = config_toks[0];
00218             facility_string = config_toks[1];
00219             /* split host_string into "host" vs. "server" vs. "port" */
00220             host_toks = mSplit(host_string, "=:", 3, &num_host_toks, 0);
00221             if(num_host_toks > 0 && strcmp(host_toks[0], "host") != 0 )
00222             {
00223                 FatalError("%s(%d) => Badly formed alert_syslog 'host' "
00224                         "argument ('%s')\n", 
00225                         file_name, file_line, host_string);
00226             }
00227             /* check for empty strings */
00228             if((num_host_toks >= 1 && strlen(host_toks[0]) == 0) ||
00229                     (num_host_toks >= 2 && strlen(host_toks[1]) == 0) ||
00230                     (num_host_toks >= 3 && strlen(host_toks[2]) == 0))
00231             {
00232                 FatalError("%s(%d) => Badly formed alert_syslog 'host' "
00233                         "argument ('%s')\n", 
00234                         file_name, file_line, host_string);
00235             }
00236             switch(num_host_toks)
00237             {
00238                 case 2:  /* ie,  host=localhost (defaults to port 514) */
00239                     strncpy(pv.syslog_server, host_toks[1], STD_BUF-1);
00240                     pv.syslog_server_port = DEFAULT_SYSLOG_PORT;  /* default */
00241                     break;
00242 
00243                 case 3:  /* ie.  host=localhost:514 */
00244                     strncpy(pv.syslog_server, host_toks[1], STD_BUF-1);
00245                     pv.syslog_server_port = atoi(host_toks[2]);
00246                     if( pv.syslog_server_port == 0 )
00247                     {
00248                         pv.syslog_server_port = DEFAULT_SYSLOG_PORT; /*default*/
00249                         LogMessage("WARNING %s(%d) => alert_syslog port "
00250                                 "appears to be non-numeric ('%s').  Defaulting " 
00251                                 "to port %d!\n", file_name, file_line, 
00252                                 host_toks[2], DEFAULT_SYSLOG_PORT);
00253                                 
00254                     }
00255                     break;
00256 
00257                 default:  /* badly formed, should never occur */
00258                     FatalError("%s(%d) => Badly formed alert_syslog 'host' "
00259                             "argument ('%s')\n", 
00260                             file_name, file_line, host_string);
00261             }
00262             mSplitFree(&host_toks, num_host_toks);
00263             break;
00264 
00265         default:
00266             FatalError("%s(%d) => Badly formed alert_syslog arguments ('%s')\n",
00267                     file_name, file_line, args);
00268     }
00269 
00270     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Logging alerts to syslog "
00271                 "server %s on port %d\n", pv.syslog_server, 
00272                 pv.syslog_server_port););
00273     mSplitFree(&config_toks, num_facility_toks);
00274 #endif /* WIN32 */
00275 
00276 
00277 
00278     /* tokenize the facility/priority argument list */
00279     facility_toks = mSplit(facility_string, " |", 31, &num_facility_toks, '\\');
00280 
00281     for(i = 0; i < num_facility_toks; i++)
00282     {
00283         if(*facility_toks[i] == '$')
00284         {
00285             if((tmp = VarGet(facility_toks[i]+1)) == NULL)
00286             {
00287                 FatalError("%s(%d) => Undefined variable %s\n", 
00288                         file_name, file_line, facility_toks[i]);
00289             }
00290         }
00291         else
00292         {
00293             tmp = facility_toks[i];
00294         }
00295 
00296         /* possible openlog options */
00297 
00298 #ifdef LOG_CONS 
00299         if(!strcasecmp("LOG_CONS", tmp))
00300         {
00301             data->options |= LOG_CONS;
00302         }
00303         else
00304 #endif
00305 #ifdef LOG_NDELAY 
00306         if(!strcasecmp("LOG_NDELAY", tmp))
00307         {
00308             data->options |= LOG_NDELAY;
00309         }
00310         else
00311 #endif
00312 #ifdef LOG_PERROR 
00313         if(!strcasecmp("LOG_PERROR", tmp))
00314         {
00315             data->options |= LOG_PERROR;
00316         }
00317         else
00318 #endif
00319 #ifdef LOG_PID 
00320         if(!strcasecmp("LOG_PID", tmp))
00321         {
00322             data->options |= LOG_PID;
00323         }
00324         else
00325 #endif
00326 #ifdef LOG_NOWAIT
00327         if(!strcasecmp("LOG_NOWAIT", tmp))
00328         {
00329             data->options |= LOG_NOWAIT;
00330         }
00331         else
00332 #endif
00333         /* possible openlog facilities */
00334 
00335 #ifdef LOG_AUTHPRIV 
00336         if(!strcasecmp("LOG_AUTHPRIV", tmp))
00337         {
00338             data->facility = LOG_AUTHPRIV;
00339         }
00340         else
00341 #endif
00342 #ifdef LOG_AUTH 
00343         if(!strcasecmp("LOG_AUTH", tmp))
00344         {
00345             data->facility = LOG_AUTH;
00346         }
00347         else
00348 #endif
00349 #ifdef LOG_DAEMON 
00350         if(!strcasecmp("LOG_DAEMON", tmp))
00351         {
00352             data->facility = LOG_DAEMON;
00353         }
00354         else
00355 #endif
00356 #ifdef LOG_LOCAL0 
00357         if(!strcasecmp("LOG_LOCAL0", tmp))
00358         {
00359             data->facility = LOG_LOCAL0;
00360         }
00361         else
00362 #endif
00363 #ifdef LOG_LOCAL1 
00364         if(!strcasecmp("LOG_LOCAL1", tmp))
00365         {
00366             data->facility = LOG_LOCAL1;
00367         }
00368         else
00369 #endif
00370 #ifdef LOG_LOCAL2 
00371         if(!strcasecmp("LOG_LOCAL2", tmp))
00372         {
00373             data->facility = LOG_LOCAL2;
00374         }
00375         else
00376 #endif
00377 #ifdef LOG_LOCAL3 
00378         if(!strcasecmp("LOG_LOCAL3", tmp))
00379         {
00380             data->facility = LOG_LOCAL3;
00381         }
00382         else
00383 #endif
00384 #ifdef LOG_LOCAL4 
00385         if(!strcasecmp("LOG_LOCAL4", tmp))
00386         {
00387             data->facility = LOG_LOCAL4;
00388         }
00389         else
00390 #endif
00391 #ifdef LOG_LOCAL5 
00392         if(!strcasecmp("LOG_LOCAL5", tmp))
00393         {
00394             data->facility = LOG_LOCAL5;
00395         }
00396         else
00397 #endif
00398 #ifdef LOG_LOCAL6 
00399         if(!strcasecmp("LOG_LOCAL6", tmp))
00400         {
00401             data->facility = LOG_LOCAL6;
00402         }
00403         else
00404 #endif
00405 #ifdef LOG_LOCAL7 
00406         if(!strcasecmp("LOG_LOCAL7", tmp))
00407         {
00408             data->facility = LOG_LOCAL7;
00409         }
00410         else
00411 #endif
00412 #ifdef LOG_USER 
00413         if(!strcasecmp("LOG_USER", tmp))
00414         {
00415             data->facility = LOG_USER;
00416         }
00417         else
00418 #endif
00419 
00420         /* possible syslog priorities */
00421 
00422 #ifdef LOG_EMERG 
00423         if(!strcasecmp("LOG_EMERG", tmp))
00424         {
00425             data->priority = LOG_EMERG;
00426         }
00427         else
00428 #endif
00429 #ifdef LOG_ALERT 
00430         if(!strcasecmp("LOG_ALERT", tmp))
00431         {
00432             data->priority = LOG_ALERT;
00433         }
00434         else
00435 #endif
00436 #ifdef LOG_CRIT 
00437         if(!strcasecmp("LOG_CRIT", tmp))
00438         {
00439             data->priority = LOG_CRIT;
00440         }
00441         else
00442 #endif
00443 #ifdef LOG_ERR 
00444         if(!strcasecmp("LOG_ERR", tmp))
00445         {
00446             data->priority = LOG_ERR;
00447         }
00448         else
00449 #endif
00450 #ifdef LOG_WARNING 
00451         if(!strcasecmp("LOG_WARNING", tmp))
00452         {
00453             data->priority = LOG_WARNING;
00454         }
00455         else
00456 #endif
00457 #ifdef LOG_NOTICE 
00458         if(!strcasecmp("LOG_NOTICE", tmp))
00459         {
00460             data->priority = LOG_NOTICE;
00461         }
00462         else
00463 #endif
00464 #ifdef LOG_INFO 
00465         if(!strcasecmp("LOG_INFO", tmp))
00466         {
00467             data->priority = LOG_INFO;
00468         }
00469         else
00470 #endif
00471 #ifdef LOG_DEBUG 
00472         if(!strcasecmp("LOG_DEBUG", tmp))
00473         {
00474             data->priority = LOG_DEBUG;
00475         }
00476         else
00477 #endif
00478         {
00479             LogMessage("WARNING %s (%d) => Unrecognized syslog "
00480                     "facility/priority: %s\n",
00481                     file_name, file_line, tmp);
00482         }
00483     }
00484     mSplitFree(&facility_toks, num_facility_toks);
00485 
00486     return data;
00487 }
00488 
00489 
00490 /*
00491  * Function: PreprocFunction(Packet *)
00492  *
00493  * Purpose: Perform the preprocessor's intended function.  This can be
00494  *          simple (statistics collection) or complex (IP defragmentation)
00495  *          as you like.  Try not to destroy the performance of the whole
00496  *          system by trying to do too much....
00497  *
00498  * Arguments: p => pointer to the current packet data struct 
00499  *
00500  * Returns: void function
00501  *
00502  */
00503 extern OptTreeNode *otn_tmp;
00504 void AlertSyslog(Packet *p, char *msg, void *arg, Event *event)
00505 {
00506     char sip[16];
00507     char dip[16];
00508     char pri_data[STD_BUF];
00509     char ip_data[STD_BUF];
00510     char event_data[STD_BUF];
00511 #define SYSLOG_BUF  1024
00512     char event_string[SYSLOG_BUF];
00513     SyslogData *data = (SyslogData *)arg;
00514 
00515 
00516     bzero(event_string, SYSLOG_BUF);
00517 
00518     if(p && p->iph)
00519     {
00520         /*
00521          * have to do this since inet_ntoa is fucked up and writes to a static
00522          * memory location
00523          */
00524         strlcpy(sip, inet_ntoa(p->iph->ip_src), 16);
00525         strlcpy(dip, inet_ntoa(p->iph->ip_dst), 16);
00526 
00527         if(event != NULL)
00528         {
00529             snprintf(event_data, STD_BUF-1, "[%lu:%lu:%lu] ", 
00530                     (unsigned long) event->sig_generator,
00531                     (unsigned long) event->sig_id, 
00532                     (unsigned long) event->sig_rev);
00533             strlcat(event_string, event_data, SYSLOG_BUF);
00534         }
00535 
00536         if(msg != NULL)
00537         {
00538             strlcat(event_string, msg, SYSLOG_BUF);
00539         }
00540         else
00541         {
00542             strlcat(event_string, "ALERT", SYSLOG_BUF);
00543         }
00544 
00545         if(otn_tmp != NULL)
00546         {
00547             if(otn_tmp->sigInfo.classType)
00548             {
00549                 snprintf(pri_data, STD_BUF-1, " [Classification: %s] "
00550                         "[Priority: %d]:", otn_tmp->sigInfo.classType->name,
00551                         otn_tmp->sigInfo.priority); 
00552                 strlcat(event_string, pri_data, SYSLOG_BUF);
00553             }
00554             else if(otn_tmp->sigInfo.priority != 0)
00555             {
00556                 snprintf(pri_data, STD_BUF-1, "[Priority: %d]:", 
00557                         otn_tmp->sigInfo.priority); 
00558                 strlcat(event_string, pri_data, SYSLOG_BUF);
00559             }
00560         }
00561 
00562         if((p->iph->ip_proto != IPPROTO_TCP &&
00563                     p->iph->ip_proto != IPPROTO_UDP) || 
00564                 p->frag_flag)
00565         {
00566             if(!pv.alert_interface_flag)
00567             {
00568                 snprintf(ip_data, STD_BUF-1, " {%s} %s -> %s",  
00569                         protocol_names[p->iph->ip_proto], sip, dip);
00570             }
00571             else
00572             {
00573                 snprintf(ip_data, STD_BUF-1, " <%s> {%s} %s -> %s",  
00574                         PRINT_INTERFACE(pv.interface), 
00575                         protocol_names[p->iph->ip_proto], 
00576                         sip, dip);
00577             }
00578         }
00579         else
00580         {
00581             if(pv.alert_interface_flag)
00582             {
00583                 snprintf(ip_data, STD_BUF-1, " <%s> {%s} %s:%i -> %s:%i",
00584                         PRINT_INTERFACE(pv.interface), 
00585                         protocol_names[p->iph->ip_proto], sip,
00586                         p->sp, dip, p->dp);
00587             }
00588             else
00589             {
00590                 snprintf(ip_data, STD_BUF-1, " {%s} %s:%i -> %s:%i",
00591                         protocol_names[p->iph->ip_proto], sip, p->sp, 
00592                         dip, p->dp);
00593             }
00594         }
00595 
00596         strlcat(event_string, ip_data, SYSLOG_BUF);
00597 
00598         syslog(data->priority, "%s", event_string);
00599 
00600     }
00601     else  
00602     {
00603         syslog(data->priority, "%s", msg == NULL ? "ALERT!" : msg);
00604     }
00605 
00606     return;
00607 
00608 }
00609 
00610 
00611 void AlertSyslogCleanExit(int signal, void *arg)
00612 {
00613     SyslogData *data = (SyslogData *)arg;
00614     DEBUG_WRAP(DebugMessage(DEBUG_LOG, "AlertSyslogCleanExit\n"););
00615     /* free memory from SyslogData */
00616     free(data);
00617 }
00618 
00619 void AlertSyslogRestart(int signal, void *arg)
00620 {
00621     SyslogData *data = (SyslogData *)arg;
00622     DEBUG_WRAP(DebugMessage(DEBUG_LOG, "AlertSyslogRestartFunc\n"););
00623     /* free memory from SyslogData */
00624     free(data);
00625 }

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