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

spp_flow.c

Go to the documentation of this file.
00001 /**
00002  * Copyright (C) 2003 Sourcefire, Inc.
00003  *
00004  * @file   spp_flow.c
00005  * @author Chris Green <cmg@sourcefire.com>
00006  * @date   Thu May 29 11:27:17 2003
00007  * 
00008  * @brief  flow integration with snort
00009  *
00010  * The purpose of this module is to have an abstract way of detecting
00011  * significant events to various modules so that everything higher
00012  * layers see as a session can be tracked in a single spot.
00013  *
00014  * This module completely replaces spp_conversation.
00015  */
00016  
00017 /*
00018  * This program is free software; you can redistribute it and/or modify
00019  * it under the terms of the GNU General Public License as published by
00020  * the Free Software Foundation; either version 2 of the License, or
00021  * (at your option) any later version.
00022  *
00023  * This program is distributed in the hope that it will be useful,
00024  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00025  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00026  * GNU General Public License for more details.
00027  *
00028  * You should have received a copy of the GNU General Public License
00029  * along with this program; if not, write to the Free Software
00030  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00031  */
00032 
00033 #include <time.h>
00034 
00035 #include "snort.h"
00036 #include "decode.h" /* Packet */
00037 #include "debug.h" /* DEBUG_WRAP */
00038 #include "plugbase.h" /* RegisterPreprocesor */
00039 #include "util.h" /* FatalError */
00040 #include "parser.h" /* file_name, file_line */
00041 
00042 #include "spp_flow.h"
00043 #include "flow/flow.h"
00044 #include "flow/flow_cache.h"
00045 #include "flow/flow_callback.h"
00046 #include "flow/flow_class.h"
00047 #include "flow/flow_print.h"
00048 #include "flow/portscan/flowps_snort.h"
00049 
00050 #define DEFAULT_MEMCAP (1024 * 1024 * 10)
00051 #define DEFAULT_ROWS   (1024 * 4)
00052 #define DEFAULT_STAT_INTERVAL 0
00053 
00054 typedef struct _SPPFLOW_CONFIG
00055 {
00056     int stats_interval;
00057     int memcap;
00058     int rows;
00059     FLOWHASHID hashid;
00060 } SPPFLOW_CONFIG;
00061 
00062 static int s_flow_running = 0;  /**< is flow turned on? */
00063 static FLOWCACHE s_fcache;
00064 static SPPFLOW_CONFIG s_config;
00065 
00066 static int FlowParseArgs(SPPFLOW_CONFIG *config, char *args);
00067 static INLINE int FlowPacket(Packet *p);
00068 static void FlowPreprocessor(Packet *p, void *);
00069 static void FlowInit(u_char *args);
00070 static void FlowCleanExit(int signal, void *data);
00071 static void FlowRestart(int signal, void *data);
00072 static void FlowParseOption(SPPFLOW_CONFIG *config,
00073                             char *fname, int lineno,
00074                             char *key, char *value);
00075 static void DisplayFlowConfig(void);
00076 
00077 static int s_debug = 0;
00078 unsigned int giFlowbitSize = 64;
00079 
00080 /** 
00081  * Add the Flow Preprocessor to the list of things that snort can
00082  * configure.
00083  * 
00084  */
00085 void SetupFlow(void)
00086 {
00087     /* we should really create some set of structure's that we can go
00088      * register as config editors */
00089     
00090     RegisterPreprocessor("flow", FlowInit);
00091 
00092     /* setup the portscan preprocessor */
00093     SetupFlowPS();    
00094 }
00095 /** 
00096  * Condense all the checks into one places
00097  *
00098  * Must be IP
00099  * Must not be a fragment
00100  * Must not be a rebuild stream
00101  * 
00102  * @param p packet to inspect
00103  * 
00104  * @return 1 if this packet is for flow module, 0 otherwise
00105  */
00106 static INLINE int FlowPacket(Packet *p)
00107 {
00108     if(!p->iph)
00109         return 0;
00110 
00111     if(p->frag_flag)
00112         return 0;
00113 
00114     /*
00115     if(p->packet_flags & PKT_REBUILT_STREAM)
00116         return 0;
00117     */
00118 
00119     return 1;
00120 }
00121 
00122 /** 
00123  * Initialize the configuration of the flow preprocessor
00124  * 
00125  * @param args command line arguments from snort.conf
00126  */
00127 static void FlowInit(u_char *args)
00128 {
00129     static int init_once = 0;
00130     int ret;
00131     static SPPFLOW_CONFIG *config = &s_config;
00132     
00133     if(init_once)
00134         FatalError("%s(%d) Unable to reinitialize flow!\n", file_name, file_line);
00135     else
00136         init_once = 1;
00137 
00138     /* setup the defaults */
00139     config->stats_interval = DEFAULT_STAT_INTERVAL;
00140     config->memcap = DEFAULT_MEMCAP;
00141     config->rows   = DEFAULT_ROWS;
00142     config->hashid = HASH2; /* use the quickest hash by default */
00143     FlowParseArgs(config, args);
00144 
00145     if((ret = flowcache_init(&s_fcache, config->rows, config->memcap, 
00146                              giFlowbitSize, config->hashid)) != FLOW_SUCCESS)
00147     {
00148         FatalError("Unable to initialize the flow cache!"
00149                    "-- try more memory (current memcap is %d)\n", config->memcap);
00150     }
00151 
00152     DisplayFlowConfig();
00153 
00154     s_flow_running = 1;
00155     
00156     AddFuncToPreprocList(FlowPreprocessor);
00157     AddFuncToCleanExitList(FlowCleanExit, NULL);
00158     AddFuncToRestartList(FlowRestart, NULL);
00159 }
00160 
00161 static void FlowRestart(int signal, void *data)
00162 {
00163     return;
00164 }
00165 
00166 static void FlowCleanExit(int signal, void *data)
00167 {
00168     fflush(stdout);
00169     LogMessage("Final Flow Statistics\n");
00170     if(!pv.quiet_flag)
00171         flowcache_stats(stdout, &s_fcache);
00172     fflush(stdout);
00173     flowcache_destroy(&s_fcache);
00174     return;
00175 }
00176 
00177 /** 
00178  * The runtime entry point for the flow module from snort
00179  *
00180  * 1) Assign each packet a flow
00181  * 2) Perform various callbacks based on the parameters for the flow
00182  * 
00183  * @param p packet to process
00184  */
00185 static void FlowPreprocessor(Packet *p, void *context)
00186 {
00187     int flow_class; /**< addressing scheme to use */
00188     int direction; /**< which way does the flow go */
00189     static time_t last_output = 0;
00190     FLOWKEY search_key;
00191     FLOW *fp;
00192     FLOWCACHE *fcache = &s_fcache;
00193     FLOWPACKET *pkt = (FLOWPACKET *) p;
00194         
00195     if(!FlowPacket(p))
00196     {
00197         return;
00198     }
00199     
00200     /* first find the addressing schema */
00201     if(flow_classifier(pkt, &flow_class) != FLOW_SUCCESS)
00202     {
00203         //LogMessage("Error classifying packet\n");
00204         return;
00205     }
00206 
00207     switch(flow_class)
00208     {
00209     case FLOW_IPV4:
00210         if(flowkey_make(&search_key, pkt) != FLOW_SUCCESS)
00211         {
00212             ErrorMessage("Unable to make a search key\n");
00213             return;
00214         }
00215         break;
00216     default:
00217         ErrorMessage("Unknown Flow Type: %d\n", flow_class);
00218         return;
00219     }
00220 
00221     /** this should return a direction too for the key */
00222     //printf("flowkey: "); flowkey_fprint(stdout, &search_key); printf("\n");
00223     
00224     if(flowcache_find(fcache, &search_key, &fp, &direction) == FLOW_SUCCESS)
00225     {
00226         /*
00227         **  We set flows for rebuilt pkts if there is one, otherwise
00228         **  we just bail.
00229         */
00230         if(p->packet_flags & PKT_REBUILT_STREAM)
00231         {
00232             p->flow = fp;
00233             return;
00234         }
00235 
00236         if(direction == FROM_RESPONDER && fp->stats.packets_recv == 0)
00237         {
00238             /* this is the first packet back from the guy */           
00239             flow_callbacks(FLOW_FIRST_BIDIRECTIONAL, fp, direction, p);
00240         }
00241 
00242         flow_callbacks(FLOW_ADDITIONAL, fp, direction, pkt);
00243     }
00244     else
00245     {
00246         /*
00247         **  If there's no flow for a rebuilt stream, then we don't
00248         **  care because something is screwed up.
00249         */
00250         if(p->packet_flags & PKT_REBUILT_STREAM)
00251         {
00252             return;
00253         }
00254 
00255         if(flowcache_newflow(fcache, &search_key, &fp) != FLOW_SUCCESS)
00256         {
00257             flow_printf("***ERROR: "); flowkey_print(&search_key); flow_printf("\n");
00258         }
00259 
00260         direction = FROM_INITIATOR;
00261 
00262         flow_callbacks(FLOW_NEW, fp, FROM_INITIATOR, pkt);
00263     }
00264 
00265     fp->stats.direction = direction;
00266 
00267     /* printout some verbose statistics */
00268     if(s_config.stats_interval  &&
00269        ((last_output + s_config.stats_interval) <= p->pkth->ts.tv_sec))
00270     {
00271         last_output =  p->pkth->ts.tv_sec;
00272 
00273         if(!pv.quiet_flag)
00274             flowcache_stats(stdout, fcache);
00275     }
00276 
00277     p->flow = fp;
00278 
00279 }
00280 
00281 /** 
00282  * See if the flow needs to be shutdown and remove it from the
00283  * cache. This function should be placed AFTER all detection type
00284  * components.
00285  * 
00286  * @param p packet
00287  * 
00288  * @return 0 on sucess
00289  */
00290 int CheckFlowShutdown(Packet *p)
00291 {
00292     FLOWCACHE *fcache = &s_fcache;
00293 
00294     FLOW *flowp = (FLOW *) p->flow;
00295     
00296     if(flowp != NULL)
00297     {
00298         if(flow_checkflag(flowp, FLOW_CLOSEME))
00299         {
00300             /* allow all the submodules to trigger their final stand */            
00301             flow_callbacks(FLOW_SHUTDOWN, flowp, FROM_INITIATOR, p);
00302             
00303             if(flowcache_releaseflow(fcache, &flowp) != FLOW_SUCCESS)
00304             {
00305                 flow_printf("Can't release flow %p\n", p->flow);
00306                 return FLOW_BADJUJU;
00307             }
00308         }
00309     }
00310 
00311     p->flow = NULL;
00312 
00313     return FLOW_SUCCESS;
00314 }
00315 
00316 
00317 static int FlowParseArgs(SPPFLOW_CONFIG *config, char *args)
00318 {
00319     char *key, *value;
00320     char *myargs = NULL;
00321     const char *delim = " \t";
00322     
00323     if(args)
00324     {
00325         if(s_debug > 5)
00326             flow_printf("I'm parsing %s!\n", args);
00327         
00328         myargs = strdup(args);
00329 
00330         if(myargs == NULL)
00331             FatalError("Out of memory parsing flow arguments\n");
00332     }
00333     else
00334     {
00335         if(s_debug > 5)
00336             flow_printf("nothing to parse for this flow!\n");
00337         
00338         return 0;
00339     }
00340 
00341     key = strtok(myargs, delim);
00342 
00343     while(key != NULL)
00344     {
00345         value = strtok(NULL, delim);
00346 
00347         if(!value)
00348         {
00349             FatalError("%s(%d) key %s has no value", file_name, file_line); 
00350         }
00351 
00352         FlowParseOption(config, file_name, file_line, key, value);                
00353         key = strtok(NULL, delim);
00354     }
00355 
00356     if(myargs)
00357         free(myargs);
00358     
00359     return 0;
00360 }
00361 
00362 static void FlowParseOption(SPPFLOW_CONFIG *config,
00363                             char *fname, int lineno,
00364                             char *key, char *value)
00365 {
00366     if(!strcasecmp(key, "memcap"))
00367     {
00368         config->memcap = atoi(value);        
00369     }
00370     else if(!strcasecmp(key, "rows"))
00371     {
00372         config->rows = atoi(value);        
00373     }   
00374     else if(!strcasecmp(key, "stats_interval"))
00375     {
00376         config->stats_interval = atoi(value);
00377     }
00378     else if(!strcasecmp(key, "hash"))
00379     {
00380         switch(atoi(value))
00381         {
00382         case 1:
00383             config->hashid = HASH1;
00384             break;
00385         case 2:
00386             config->hashid = HASH2;
00387             break;
00388         default:
00389             FatalError("%s(%d)  Unknown Hash Type: key(%s) value(%s)\n",
00390                        fname, lineno, key, value);
00391         }
00392     }
00393 
00394     else
00395     {
00396         FatalError("%s(%d)  Unknown Arguments: key(%s) value(%s)\n",
00397                    fname, lineno, key, value);
00398     }
00399     
00400 }
00401 
00402 /** 
00403  * Print out some of the common information about the Flow Processor
00404  * configuration
00405  * 
00406  */
00407 static void DisplayFlowConfig(void)
00408 {
00409     SPPFLOW_CONFIG *cp = &s_config;
00410     FLOWCACHE *fcp = &s_fcache;
00411     
00412     LogMessage(",-----------[Flow Config]----------------------\n");
00413     LogMessage("| Stats Interval:  %d\n", cp->stats_interval);
00414     LogMessage("| Hash Method:     %d\n", cp->hashid);
00415     LogMessage("| Memcap:          %d\n", cp->memcap);
00416     LogMessage("| Rows  :          %d\n", flowcache_row_count(fcp));
00417     LogMessage("| Overhead Bytes:  %d(%%%.2lf)\n",
00418                flowcache_overhead_bytes(fcp),
00419                calc_percent(flowcache_overhead_bytes(fcp),cp->memcap));
00420     LogMessage("`----------------------------------------------\n");
00421 
00422 }
00423 
00424 /** 
00425  * Return 1 if spp_flow has been configured
00426  * 
00427  * 
00428  * @return 1 if spp_flow is enabled
00429  */
00430 int SppFlowIsRunning(void)
00431 {
00432     return s_flow_running;
00433 }

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