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

xlink2state.c

Go to the documentation of this file.
00001 
00002 
00003 /* x-link2state 
00004  * 
00005  * Copyright (C) 2005 Sourcefire,Inc.
00006  *
00007  */
00008 
00009 #include <stdlib.h>
00010 #include <string.h>
00011 
00012 /*
00013  * If you're going to issue any alerts from this preproc you 
00014  * should include generators.h and event_wrapper.h
00015  */
00016 #include "generators.h"
00017 #include "event_wrapper.h"
00018 #include "event_queue.h"
00019 
00020 #include "util.h"
00021 #include "plugbase.h"
00022 #include "parser.h"
00023 #include "snort.h"
00024 
00025 /* In case we need to drop this packet */
00026 #include "inline.h"
00027 
00028 /* Okay, we may need to threshold this crap, too */
00029 #include "sfthreshold.h"
00030 
00031 /*
00032  * put in other includes as necessary
00033  */
00034 #include "debug.h"
00035 
00036 #include "str_search.h"
00037 #include "xlink2state.h"
00038 
00039 /* Pointer to current session data */
00040 XLINK2STATE *_xlink;
00041 static u_int       _xlink2state_ports[65535];
00042 static u_int       _xlink2state_disabled = 0;
00043 static u_int       _xlink2state_drop = 0;
00044 static Packet      *_xlink2state_pkt = NULL;
00045 
00046 /*
00047 **  Port list delimiters
00048 */
00049 #define START_LIST      "{"
00050 #define END_LIST        "}"
00051 #define PORTS           "ports"
00052 #define DISABLE         "disable"
00053 #define INLINE_DROP     "drop"
00054 #define CONF_SEPARATORS " \t\n\r"
00055 
00056 #define ERRSTRLEN   512
00057 
00058 /*
00059  * Initialize SMTP preprocessor
00060  *
00061  * @param  none
00062  *
00063  * @return none
00064  */
00065 void XLINK2STATE_Init(void)
00066 {
00067     /*  Set up commands we will watch for */
00068     SearchInit(1);
00069     
00070     /*  Set up commands we will watch for */
00071     SearchInit(1);
00072     
00073     SearchAdd(0, "X-LINK2STATE", 0);
00074     
00075     SearchPrepPatterns(0);
00076 
00077 }
00078 
00079 
00080 /*
00081  * Free XLINK2STATE-specific related to this session
00082  *
00083  * @param   v   pointer to XLINK2STATE session structure
00084  *
00085  * @return  none
00086  */
00087 void XLINK2STATE_SessionFree(void * v)
00088 {
00089     XLINK2STATE *x = (XLINK2STATE *) v;
00090 
00091     if ( x )
00092         free(x);
00093     return;
00094 }
00095 
00096 
00097 /*
00098  * Do first-packet setup
00099  *
00100  * @param   p   standard Packet structure
00101  *
00102  * @return  none
00103  */
00104 static void XLINK2STATE_Setup(Packet *p)
00105 {
00106     Session      *ssnptr;
00107 
00108     /*  Get session pointer */
00109     ssnptr = (Session *) (p->ssnptr);
00110 
00111     if ( ssnptr && ssnptr->preproc_data == NULL )
00112     {
00113         XLINK2STATE *x = (XLINK2STATE *) malloc(sizeof(XLINK2STATE));
00114         if ( x == NULL )
00115         {
00116             FatalError("%s(%d) => Failed to allocate for X-Link2State session data\n", 
00117                     file_name, file_line);
00118             return;
00119         }
00120         memset(x, 0, sizeof(XLINK2STATE));
00121         ssnptr->preproc_data = x;
00122         ssnptr->preproc_free = XLINK2STATE_SessionFree;
00123     }
00124 }
00125 
00126 /*
00127  * Given a server configuration and a port number, we decide if the port is
00128  *  in the SMTP server port list.
00129  *
00130  *  @param  port       the port number to compare with the configuration
00131  *
00132  *  @return integer
00133  *  @retval  0 means that the port is not a server port
00134  *  @retval !0 means that the port is a server port
00135  */
00136 static int IsServer(unsigned short port)
00137 {
00138     if( _xlink2state_ports[port] )
00139     {
00140         return 1;
00141     }
00142 
00143     return 0;
00144 }
00145 
00146 static char * safe_strchr(char *buf, char c, u_int len)
00147 {
00148     char *p = buf;
00149     int i = 0;
00150 
00151     while ( i < len )
00152     {
00153         if ( *p == c )
00154         {
00155             return p;
00156         }
00157         i++;
00158         p++;
00159     }
00160 
00161     return NULL;
00162 }
00163 
00164 int ParseXLink2State(int id, u_int8_t *x)
00165 {
00166     char *eq;
00167     char *start;
00168     char *lf;
00169     int   len = 0;
00170     u_int x_len;
00171 
00172     /* Calculate length from pointer to end of packet data */
00173     x_len = _xlink2state_pkt->dsize - (x - _xlink2state_pkt->data);
00174 
00175     eq = safe_strchr(x, '=', x_len);
00176     if ( !eq )
00177         return 0;
00178 
00179     /*  Look for one of two patterns:
00180 
00181         ... CHUNK={0000006d} MULTI (5) ({00000000051} ...
00182         ... CHUNK=AAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n
00183      */
00184     if ( *(eq+1) == '{' )
00185     {
00186         /* Parse length - can we always trust it? */
00187         start = eq + 2;
00188         sscanf(start, "%x", &len);
00189     }
00190     else
00191     {
00192         start = eq + 1;
00193     }
00194 
00195     if ( len == 0 )
00196     {
00197         lf = safe_strchr(x, '\n', x_len);
00198         if ( !lf )
00199             return 0;
00200 
00201         len = lf - start;
00202     }
00203     _xlink->length += len;
00204 
00205     if ( _xlink->length > 1024 )
00206     {
00207         /* Need to drop the packet if we're told to
00208          * and we're inline mode (outside of whether its
00209          * thresholded). */
00210         if (_xlink2state_drop && InlineMode())
00211         {
00212             _xlink2state_pkt->packet_flags |= PKT_INLINE_DROP; 
00213             InlineDrop();
00214         }
00215 
00216         /* Are we thresholding this event? */
00217         if( !sfthreshold_test( GENERATOR_SMTP,
00218                                1,
00219                                _xlink2state_pkt->iph->ip_src.s_addr,
00220                                _xlink2state_pkt->iph->ip_dst.s_addr,
00221                                _xlink2state_pkt->pkth->ts.tv_sec) )
00222         {
00223             _xlink->alerted = 1;
00224             return 1;
00225         }
00226 
00227         SnortEventqAdd(GENERATOR_SMTP, 1, 1, 0, 3, "X-Link2State length greater than 1024", 0);
00228         _xlink->alerted = 1;
00229 
00230         return 1;
00231     }
00232 
00233     return 0;
00234 }
00235 
00236 /*
00237  * Callback function from search
00238  *
00239  * @param   id      id in array of search strings from _smtp_config.cmds
00240  * @param   index   index in array of search strings from _smtp_config.cmds
00241  * @param   data    buffer passed in to search function
00242  *
00243  * @return response
00244  * @retval 1        commands caller to stop searching
00245  */
00246 int StrFound(void *id, int index, void *data)
00247 {
00248     int  iid = (int)(long) id;
00249     u_int8_t *buf = (char *) data;
00250     u_int8_t *ptr = buf + index;
00251     
00252     /* Found X-LINK2STATE, parse lengths */
00253 
00254     /* Returning zero tells search engine to keep sending matches */
00255     return ParseXLink2State(iid, ptr);
00256 }
00257 
00258 /*
00259  * Process client packet
00260  *
00261  * @param   packet  standard Packet structure
00262  *
00263  * @return  none
00264  */
00265 static void XLINK2STATE_ProcessPacket(Packet *p)
00266 {
00267     int  strFound;
00268     Session *ssnptr = NULL;
00269 
00270     if(!p->ssnptr)
00271     {
00272         return;
00273     }
00274     ssnptr = (Session *)p->ssnptr;
00275 
00276     _xlink = (XLINK2STATE *) ssnptr->preproc_data;
00277 
00278     /* Save the packet pointer, so we can set the
00279      * packet's drop flags and check for thresholding. */
00280     _xlink2state_pkt = p;
00281 
00282     /* Only need to alert once per session */
00283     if ( _xlink->alerted )
00284     {
00285         if (_xlink2state_drop && InlineMode())
00286         {
00287             _xlink2state_pkt->packet_flags |= PKT_INLINE_DROP; 
00288             InlineDrop();
00289         }
00290         return;
00291     }
00292 
00293     /*  Check for X-LINK2STATE string */
00294     strFound = SearchFindString(0, p->data, p->dsize, StrFound);
00295 
00296 }
00297 
00298 /*
00299  * Entry point to snort preprocessor for each packet
00300  *
00301  * @param   packet  standard Packet structure
00302  *
00303  * @return  none
00304  */
00305 void SnortXLINK2STATE(Packet *p)
00306 {
00307     /* See if we are disabled */
00308     if ( _xlink2state_disabled )
00309         return;
00310 
00311     /*  Make sure it's traffic we're interested in
00312         Only client traffic for X-LINK2STATE */
00313     if ( !IsServer(p->dp) )
00314         return;
00315 
00316        /*  Ignore if not enough data */
00317     if (p->dsize < 18)
00318         return;
00319     
00320     XLINK2STATE_Setup(p);
00321     
00322     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, " <SMTP packet from client>\n"););
00323 
00324     if (p->packet_flags & PKT_STREAM_INSERT)
00325     {
00326         /* Packet will be rebuilt, so wait for it */
00327         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Client packet will be reassembled\n"));
00328         return;
00329     }
00330    
00331     /* Process as a client packet */
00332     XLINK2STATE_ProcessPacket(p);
00333 }
00334 
00335 
00336 
00337 static int PrintConfig(void)
00338 {
00339     int i;
00340     char buf[STD_BUF+1];
00341 
00342     LogMessage("X-Link2State Config:\n");
00343     
00344     memset(buf, 0, STD_BUF+1);
00345     snprintf(buf, STD_BUF, "    Ports: ");
00346     for(i = 0; i < 65536; i++)
00347     {
00348         if(_xlink2state_ports[i])
00349         {
00350             sfsnprintfappend(buf, STD_BUF, "%d ", i);
00351         }
00352     }
00353     LogMessage("%s\n", buf);
00354     if (InlineMode())
00355         LogMessage("    Drop Packets (inline only): %s\n", _xlink2state_drop ? "YES" : "NO");
00356     
00357     return 0;
00358 }
00359 
00360 
00361 /*
00362 **  NAME
00363 **    ProcessPorts::
00364 **
00365 **  Process the port list.
00366 **
00367 **  This configuration is a list of valid ports and is ended by a 
00368 **  delimiter.
00369 **
00370 **  @param ErrorString error string buffer
00371 **  @param ErrStrLen   the length of the error string buffer
00372 **
00373 **  @return an error code integer 
00374 **          (0 = success, >0 = non-fatal error, <0 = fatal error)
00375 **
00376 **  @retval  0 successs
00377 **  @retval -1 generic fatal error
00378 **  @retval  1 generic non-fatal error
00379 */
00380 static int ProcessPorts(char *ErrorString, int ErrStrLen)
00381 {
00382     char *pcToken;
00383     char *pcEnd;
00384     int  iPort;
00385     int  iEndPorts = 0;
00386 
00387     /*  Clear out default port */
00388     _xlink2state_ports[SMTP_DEFAULT_SERVER_PORT] = 0;
00389 
00390     pcToken = strtok(NULL, CONF_SEPARATORS);
00391     if(!pcToken)
00392     {
00393         snprintf(ErrorString, ErrStrLen,
00394                 "Invalid port list format.");
00395 
00396         return -1;
00397     }
00398 
00399     if(strcmp(START_LIST, pcToken))
00400     {
00401         snprintf(ErrorString, ErrStrLen,
00402                 "Must start a port list with the '%s' token.",
00403                 START_LIST);
00404 
00405         return -1;
00406     }
00407     
00408     while((pcToken = strtok(NULL, CONF_SEPARATORS)))
00409     {
00410         if(!strcmp(END_LIST, pcToken))
00411         {
00412             iEndPorts = 1;
00413             break;
00414         }
00415 
00416         iPort = strtol(pcToken, &pcEnd, 10);
00417 
00418         /*
00419         **  Validity check for port
00420         */
00421         if(*pcEnd)
00422         {
00423             snprintf(ErrorString, ErrStrLen,
00424                     "Invalid port number.");
00425 
00426             return -1;
00427         }
00428 
00429         if(iPort < 0 || iPort > 65535)
00430         {
00431             snprintf(ErrorString, ErrStrLen,
00432                     "Invalid port number.  Must be between 0 and "
00433                     "65535.");
00434 
00435             return -1;
00436         }
00437 
00438         _xlink2state_ports[iPort] = 1;
00439     }
00440 
00441     if(!iEndPorts)
00442     {
00443         snprintf(ErrorString, ErrStrLen,
00444                 "Must end '%s' configuration with '%s'.",
00445                 PORTS, END_LIST);
00446 
00447         return -1;
00448     }
00449 
00450     return 0;
00451 }
00452 
00453 /*
00454  * Function: XLINK2STATE_ParseArgs(char *)
00455  *
00456  * Purpose: Process the preprocessor arguments from the rules file and 
00457  *          initialize the preprocessor's data struct.  This function doesn't
00458  *          have to exist if it makes sense to parse the args in the init 
00459  *          function.
00460  *
00461  * Arguments: args => argument list
00462  *
00463  * Returns: void function
00464  *
00465  */
00466 void XLINK2STATE_ParseArgs(u_char *args)
00467 {
00468     int   ret = 0;
00469     char *arg;
00470     char errStr[ERRSTRLEN];
00471     int  errStrLen = ERRSTRLEN;
00472     
00473     _xlink2state_ports[SMTP_DEFAULT_SERVER_PORT] = 1;
00474 
00475     if ( args == NULL )
00476     {
00477         return;
00478     }
00479 
00480     arg = strtok(args, CONF_SEPARATORS);
00481     
00482     while ( arg != NULL )
00483     {
00484         if ( !strcasecmp(PORTS, arg) )
00485         {
00486             ret = ProcessPorts(errStr, errStrLen);
00487             if ( ret == -1 )
00488                 break;
00489         }
00490         else if ( !strcasecmp(DISABLE, arg) )
00491         {
00492             _xlink2state_disabled = 1;
00493         }
00494         else if ( !strcasecmp(INLINE_DROP, arg) )
00495         {
00496             if (InlineMode())
00497                 _xlink2state_drop = 1;
00498             else
00499                 LogMessage("%s(%d) WARNING: drop keyword ignored."
00500                            "snort is not in inline mode\n",
00501                            file_name, file_line);
00502         }
00503 
00504         /*  Get next token */
00505         arg = strtok(NULL, CONF_SEPARATORS);
00506     }
00507 
00508     if ( ret < 0 )
00509     {
00510         /*
00511         **  Fatal Error, log error and exit.
00512         */
00513         if(*errStr)
00514         {
00515             FatalError("%s(%d) => %s\n", 
00516                     file_name, file_line, errStr);
00517         }
00518         else
00519         {
00520             FatalError("%s(%d) => Undefined Error.\n", 
00521                         file_name, file_line);
00522         }
00523     }
00524 
00525     PrintConfig();
00526 }
00527 

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