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

spo_alert_sf_socket.c

Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 2003 Sourcefire, Inc.
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 
00019 /* $Id$ */
00020 
00021 /* We use some Linux only socket capabilities */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026 
00027 #ifdef LINUX
00028 
00029 #include "spo_plugbase.h"
00030 
00031 #include "event.h"
00032 #include "rules.h"
00033 #include "debug.h"
00034 #include "util.h"
00035 #include <sys/socket.h>
00036 #include <sys/un.h>
00037 #include <errno.h>
00038 #include <stdlib.h>
00039 
00040 /* error result codes */
00041 #define SNORT_SUCCESS 0
00042 #define SNORT_EINVAL 1
00043 #define SNORT_ENOENT 2
00044 #define SNORT_ENOMEM 3
00045 
00046 static int configured = 0;
00047 static int connected = 0;
00048 static int sock = -1;
00049 static struct sockaddr_un sockAddr;
00050 
00051 extern RuleListNode *RuleLists;
00052 
00053 typedef struct _SnortActionRequest
00054 {
00055     u_int32_t event_id;
00056     u_int32_t tv_sec;
00057     u_int32_t generator;
00058     u_int32_t sid;
00059     u_int32_t src_ip;
00060     u_int32_t dest_ip;
00061     u_int16_t sport;
00062     u_int16_t dport;
00063     u_int8_t protocol;
00064 } SnortActionRequest;
00065 
00066 static void AlertSFSocket_Init(u_char *args);
00067 static void AlertSFSocketSid_Init(u_char *args);
00068 void AlertSFSocket(Packet *packet, char *msg, void *arg, Event *event);
00069 
00070 static int AlertSFSocket_Connect(void);
00071 static OptTreeNode *OptTreeNode_Search(u_int32_t sid);
00072 static int SignatureAddOutputFunc(u_int32_t sid, 
00073         void (*outputFunc)(Packet *, char *, void *, Event *),
00074         void *args);
00075 int String2ULong(char *string, unsigned long *result);
00076 
00077 void AlertSFSocket_Setup(void)
00078 {
00079     RegisterOutputPlugin("alert_sf_socket", NT_OUTPUT_ALERT, 
00080             AlertSFSocket_Init);
00081     RegisterOutputPlugin("alert_sf_socket_sid", NT_OUTPUT_ALERT,
00082             AlertSFSocketSid_Init);
00083     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"Output plugin: AlertSFSocket "
00084                 "registered\n"););
00085 }
00086 
00087 /* this is defined in linux/un.h (see aldo sys/un.h) */
00088 #ifndef UNIX_PATH_MAX
00089 #define UNIX_PATH_MAX 108
00090 #endif
00091 
00092 static void AlertSFSocket_Init(u_char *args)
00093 {
00094     /* process argument */
00095     char *sockname;
00096 
00097     if(!args)
00098         FatalError("ERROR: AlertSFSocket: must specify a socket name\n");
00099 
00100     sockname = args;
00101 
00102     if(strlen(sockname) == 0)
00103         FatalError("ERROR: AlertSFSocket: must specify a socket name\n");
00104     
00105     if(strlen(sockname) > UNIX_PATH_MAX - 1)
00106         FatalError("ERROR: AlertSFSocket: socket name must be less than %i "
00107                 "characters\n", UNIX_PATH_MAX - 1);
00108     
00109     /* create socket */
00110     if((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
00111     {
00112         FatalError("ERROR: Unable to create socket: %s\n", strerror(errno));
00113     }
00114 
00115     memset(&sockAddr, 0, sizeof(sockAddr));
00116     sockAddr.sun_family = AF_UNIX;
00117     memcpy(sockAddr.sun_path + 1, sockname, strlen(sockname));
00118     
00119     if(AlertSFSocket_Connect() == 0)
00120         connected = 1;
00121 
00122     configured = 1;
00123 
00124     return;
00125 }
00126 
00127 static void AlertSFSocketSid_Init(u_char *args)
00128 {
00129     unsigned long sidValue;
00130     int rval = 0;
00131     
00132     /* check configured value */
00133     if(!configured)
00134         FatalError("AlertSFSocket must be configured before attaching it to a "
00135                 "sid");
00136     
00137     if(String2ULong(args, &sidValue))
00138         FatalError("Invalid argument '%s' to alert_sf_socket_sid\n", args);
00139 
00140     rval = SignatureAddOutputFunc((u_int32_t)sidValue, AlertSFSocket, NULL);
00141 
00142     switch(rval)
00143     {
00144         case SNORT_SUCCESS:
00145             DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "SFSocket output enabled for "
00146                         "sid %u.\n", sidValue););
00147             break;
00148         case SNORT_EINVAL:
00149             DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Invalid argument "
00150                         "attempting to attach output for sid %u.\n", 
00151                         sidValue););
00152             break;
00153         case SNORT_ENOENT:
00154             LogMessage("No entry found.  SFSocket output not enabled for "
00155                     "sid %lu.\n", sidValue);
00156             break;
00157         case SNORT_ENOMEM:
00158             FatalError("Out of memory");
00159             break;
00160     }
00161 }
00162 
00163 static int AlertSFSocket_Connect(void)
00164 {
00165     /* check sock value */
00166     if(sock == -1)
00167         FatalError("ERROR: AlertSFSocket: Invalid socket\n");
00168 
00169     if(connect(sock, (struct sockaddr *)&sockAddr, sizeof(sockAddr)) == -1)
00170     {
00171         if(errno == ECONNREFUSED || errno == ENOENT)
00172         {
00173             LogMessage("WARNING: AlertSFSocket: Unable to connect to socket: "
00174                     "%s\n", strerror(errno));
00175             return 1;
00176         }
00177         else
00178         {
00179             FatalError("ERROR: AlertSFSocket: Unable to connect to socket "
00180                     "(%i): %s\n", errno, strerror(errno));
00181         }
00182     }
00183     return 0;
00184 }
00185         
00186                    
00187 static SnortActionRequest sar;
00188 
00189 void AlertSFSocket(Packet *packet, char *msg, void *arg, Event *event)
00190 {
00191     int tries = 0;
00192 
00193     if(!event || !packet || !packet->iph)
00194         return;
00195 
00196     /* construct the action request */
00197     sar.event_id = event->event_id;
00198     sar.tv_sec = packet->pkth->ts.tv_sec;
00199     sar.generator = event->sig_generator;
00200     sar.sid = event->sig_id;
00201     sar.src_ip = ntohl(packet->iph->ip_src.s_addr);
00202     sar.dest_ip = ntohl(packet->iph->ip_dst.s_addr);
00203     sar.protocol = packet->iph->ip_proto;
00204     if(sar.protocol == IPPROTO_UDP || sar.protocol == IPPROTO_TCP)
00205     {
00206         sar.sport = packet->sp;
00207         sar.dport = packet->dp;
00208     }
00209     else
00210     {
00211         sar.sport = 0;
00212         sar.dport = 0;
00213     }
00214 
00215     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"AlertSFSocket fired for sid %u\n",
00216                             event->sig_id););
00217 
00218     do
00219     {
00220         tries++;
00221         /* connect as needed */
00222         if(!connected)
00223         {
00224             if(AlertSFSocket_Connect() != 0)
00225                 break;
00226             connected = 1;
00227         }
00228 
00229         /* send request */
00230         if(send(sock, &sar, sizeof(sar), 0) == sizeof(sar))
00231         {
00232             /* success */
00233             return;
00234         }
00235         /* send failed */
00236         if(errno == ENOBUFS)
00237         {
00238             LogMessage("ERROR: AlertSFSocket: out of buffer space\n");
00239             break;
00240         }
00241         else if(errno == ECONNRESET)
00242         {
00243             connected = 0;
00244             LogMessage("WARNING: AlertSFSocket: connection reset, will attempt "
00245                     "to reconnect\n");
00246         }
00247         else if(errno == ECONNREFUSED)
00248         {
00249             LogMessage("WARNING: AlertSFSocket: connection refused, "
00250                     "will attempt to reconnect\n");
00251             connected = 0;
00252         }
00253         else if(errno == ENOTCONN)
00254         {
00255             LogMessage("WARNING: AlertSFSocket: not connected, "
00256                     "will attempt to reconnect\n");
00257             connected = 0;
00258         }
00259         else
00260         {
00261             LogMessage("ERROR: AlertSFSocket: unhandled error '%i' in send(): "
00262                     "%s\n", errno, strerror(errno));
00263             connected = 0;
00264         }
00265     } while(tries <= 1);
00266     LogMessage("ERROR: AlertSFSocket: Alert not sent\n");
00267     return;
00268 }
00269 
00270 static int SignatureAddOutputFunc(u_int32_t sid, 
00271         void (*outputFunc)(Packet *, char *, void *, Event *),
00272         void *args)
00273 {
00274     OptTreeNode *optTreeNode = NULL;
00275     OutputFuncNode *outputFuncs = NULL;
00276     
00277     if(!outputFunc)
00278         return SNORT_EINVAL;  /* Invalid argument */
00279                        
00280     if(!(optTreeNode = OptTreeNode_Search(sid)))
00281     {
00282         LogMessage("Unable to find OptTreeNode for SID %u\n", sid);
00283         return SNORT_ENOENT;
00284     }
00285 
00286     if(!(outputFuncs = (OutputFuncNode *)calloc(1, sizeof(OutputFuncNode))))
00287     {
00288         LogMessage("Out of memory adding output function to SID %u\n", sid);
00289         return SNORT_ENOMEM;
00290     }
00291 
00292     outputFuncs->func = outputFunc;
00293     outputFuncs->arg = args;
00294     
00295     outputFuncs->next = optTreeNode->outputFuncs;
00296 
00297     optTreeNode->outputFuncs = outputFuncs;
00298     
00299     return SNORT_SUCCESS;
00300 }
00301 
00302 
00303 /* search for an OptTreeNode by sid */
00304 static OptTreeNode *OptTreeNode_Search(u_int32_t sid)
00305 {
00306     RuleListNode *ruleListNode = RuleLists;
00307     
00308     if(sid == 0)
00309         return NULL;
00310     
00311     while(ruleListNode)
00312     {
00313         RuleTreeNode *ruleTreeNode;
00314         ListHead *listHead = ruleListNode->RuleList;
00315         
00316         ruleTreeNode = listHead->IpList;
00317         while(ruleTreeNode)
00318         {
00319             OptTreeNode *optTreeNode;
00320 
00321             optTreeNode = ruleTreeNode->down;
00322             while(optTreeNode)
00323             {
00324                 if(optTreeNode->sigInfo.id == sid)
00325                     return optTreeNode;
00326                     
00327                 optTreeNode = optTreeNode->next;
00328             }   
00329             ruleTreeNode = ruleTreeNode->right;
00330         }
00331     
00332         ruleTreeNode = listHead->TcpList;
00333         while(ruleTreeNode)
00334         {
00335             OptTreeNode *optTreeNode;
00336 
00337             optTreeNode = ruleTreeNode->down;
00338             while(optTreeNode)
00339             {
00340                 if(optTreeNode->sigInfo.id == sid)
00341                     return optTreeNode;
00342                     
00343                 optTreeNode = optTreeNode->next;
00344             }   
00345             ruleTreeNode = ruleTreeNode->right;
00346         }
00347        
00348         ruleTreeNode = listHead->UdpList;
00349         while(ruleTreeNode)
00350         {
00351             OptTreeNode *optTreeNode;
00352 
00353             optTreeNode = ruleTreeNode->down;
00354             while(optTreeNode)
00355             {
00356                 if(optTreeNode->sigInfo.id == sid)
00357                     return optTreeNode;
00358                     
00359                 optTreeNode = optTreeNode->next;
00360             }   
00361             ruleTreeNode = ruleTreeNode->right;
00362         }
00363 
00364         ruleTreeNode = listHead->IcmpList;
00365         while(ruleTreeNode)
00366         {
00367             OptTreeNode *optTreeNode;
00368 
00369             optTreeNode = ruleTreeNode->down;
00370             while(optTreeNode)
00371             {
00372                 if(optTreeNode->sigInfo.id == sid)
00373                     return optTreeNode;
00374                     
00375                 optTreeNode = optTreeNode->next;
00376             }   
00377             ruleTreeNode = ruleTreeNode->right;
00378         }
00379         
00380         ruleListNode = ruleListNode->next;
00381     }
00382 
00383     return NULL;
00384 }
00385 
00386 int String2ULong(char *string, unsigned long *result)
00387 {
00388     unsigned long value;
00389     char *endptr;
00390     if(!string)
00391         return -1;
00392 
00393     value = strtoul(string, &endptr, 10);
00394     if(*endptr != '\0')
00395         return -1;
00396 
00397     *result = value;
00398 
00399     return 0;
00400 }
00401 
00402 
00403 #endif   /* LINUX */
00404 

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