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

flowps_snort.c

Go to the documentation of this file.
00001 /**
00002  * @file   flowps_snort.c
00003  * @author Chris Green <cmg@sourcefire.com>
00004  * @date   Fri Jun  6 14:49:30 2003
00005  * 
00006  * @brief  interface between snort & portscan
00007  * 
00008  * Implements the basic functionality required for snort+flow to
00009  * interact with a portscan procesor that accepts flow events from the
00010  * flow preprocessor.
00011  */
00012 
00013 
00014 #include "debug.h"    /* DEBUG_WRAP */
00015 #include "plugbase.h" /* RegisterPreprocesor */
00016 #include "parser.h"   /* file_name, file_line */
00017 #include "snort.h"
00018 
00019 #include "scoreboard.h"
00020 #include "server_stats.h"
00021 
00022 #include "spp_flow.h" /* make sure that spp_flow is enabled */
00023 #include "flowps.h"
00024 #include "flowps_snort.h"
00025 
00026 #include "packet_time.h"
00027 #include "event_wrapper.h"
00028 #include "generators.h"
00029 #include "common_defs.h"
00030 #include "util_str.h"
00031 #include "util_net.h"
00032 
00033 #ifndef WIN32
00034 #include <sys/socket.h>
00035 #include <netinet/in.h>
00036 #include <arpa/inet.h>
00037 #endif /* WIN32 */
00038 
00039 #include <stdlib.h>
00040 #include <ctype.h>
00041 
00042 #define PSDEFAULT_SB_ROWS_ACTIVE        1000000
00043 #define PSDEFAULT_SB_MEMCAP_ACTIVE      (ONE_MBYTE * 24)
00044 #define PSDEFAULT_SB_ROWS_SCANNER       (PSDEFAULT_SB_ROWS_ACTIVE/4)
00045 #define PSDEFAULT_SB_MEMCAP_SCANNER     (PSDEFAULT_SB_MEMCAP_ACTIVE/4)
00046 #define PSDEFAULT_UT_ROWS               1000000
00047 #define PSDEFAULT_UT_MEMCAP             (ONE_MBYTE * 24)
00048 #define PSDEFAULT_SERVER_ROWS           (1 << 16) /* 65536 */
00049 #define PSDEFAULT_SERVER_MEMCAP         (ONE_MBYTE * 2)
00050 #define PSDEFAULT_SERVER_LEARNING_TIME  (ONE_HOUR * 8)
00051 #define PSDEFAULT_SERVER_IGNORE_LIMIT   500
00052 #define PSDEFAULT_SERVER_SCANNER_LIMIT  500
00053 #define PSDEFAULT_BASE_SCORE            1
00054 #define PSDEFAULT_ALERT_ONCE            1
00055 #define PSDEFAULT_OUTPUT_MODE           VARIABLEMSG
00056 
00057 /** 25% of the memory will be the scanner table */
00058 
00059 #define PSDEFAULT_TCP_PENALTIES  1     /**< enable TCP penalities by default */
00060 
00061 /* default limits for thresholds */
00062 #define PSTALKER_FIXED_SIZE     30
00063 #define PSTALKER_SLIDING_SIZE   30    /**< window frame */
00064 #define PSTALKER_SLIDING_SCORE  30    /**< pt tally */
00065 #define PSTALKER_FIXED_SCORE    15    /**< pt tally */
00066 #define PSTALKER_WINDOW_SCALE   (0.5) /**< multiplier for wsize*/
00067 
00068 #define PSSCANNER_FIXED_SIZE     15
00069 #define PSSCANNER_SLIDING_SIZE   20    /**< window frame */
00070 #define PSSCANNER_SLIDING_SCORE  40    /**< pt tally */
00071 #define PSSCANNER_FIXED_SCORE    15    /**< pt tally */
00072 #define PSSCANNER_WINDOW_SCALE   (0.5) /**< multiplier for wsize*/
00073 
00074 #define FLOWPSMAXPKTSIZE        (IP_MAXPACKET - (IP_HEADER_LEN + ETHERNET_HEADER_LEN))
00075 
00076 static PS_TRACKER s_tracker; /* snort's portscan stracker */
00077 static int s_debug = 0;
00078 static Packet *s_pkt = NULL;  /* pktkludge output mechanism */
00079      
00080 void FlowPSRestart(int signal, void *data);
00081 void FlowPSCleanExit(int signal, void *data);
00082 static void FlowPSInit(u_char *args);
00083 static void FlowPSParseArgs(PS_CONFIG *config , char *args);
00084 static int flowps_generate_flow_event(SCORE_ENTRY *sep, FLOWPACKET *p, u_int32_t *address, FLOWPS_OUTPUT output_type, time_t cur);
00085 static int flowps_init_pkt(void);
00086  /* pktkludge output system! */
00087 static Packet *flowps_mkpacket(SCORE_ENTRY *sep, FLOWPACKET *orig_packet, u_int32_t *address, time_t cur);
00088 
00089 
00090 void FlowPSSetDefaults(PS_CONFIG *config)
00091 {
00092     flowps_mkconfig(config,
00093                     PSDEFAULT_SB_MEMCAP_ACTIVE,
00094                     PSDEFAULT_SB_ROWS_ACTIVE,
00095                     PSDEFAULT_SB_MEMCAP_SCANNER,
00096                     PSDEFAULT_SB_ROWS_SCANNER,
00097                     PSDEFAULT_UT_MEMCAP,
00098                     PSDEFAULT_UT_ROWS,
00099                     PSDEFAULT_SERVER_MEMCAP,
00100                     PSDEFAULT_SERVER_ROWS,
00101                     PSDEFAULT_SERVER_LEARNING_TIME,
00102                     PSDEFAULT_TCP_PENALTIES,
00103                     PSDEFAULT_SERVER_IGNORE_LIMIT,
00104                     PSDEFAULT_SERVER_SCANNER_LIMIT,
00105                     PSDEFAULT_BASE_SCORE,
00106                     PSDEFAULT_ALERT_ONCE,
00107                     PSDEFAULT_OUTPUT_MODE);
00108 
00109     
00110     flowps_mkthreshold(&config->limit_talker, /* threshold obj */
00111                        PSTALKER_FIXED_SIZE,  /* default fixed window */
00112                        PSTALKER_FIXED_SCORE, /* default fixed limit */
00113                        PSTALKER_SLIDING_SIZE, /* default sliding size */
00114                        PSTALKER_SLIDING_SCORE,
00115                        PSTALKER_WINDOW_SCALE); 
00116 
00117     flowps_mkthreshold(&config->limit_scanner, /* threshold obj */
00118                        PSSCANNER_FIXED_SIZE,  /* default fixed window */
00119                        PSSCANNER_FIXED_SCORE, /* default fixed limit */
00120                        PSSCANNER_SLIDING_SIZE, /* default sliding size */
00121                        PSSCANNER_SLIDING_SCORE,
00122                        PSSCANNER_WINDOW_SCALE);
00123 }
00124 
00125 void SetupFlowPS(void)
00126 {
00127     RegisterPreprocessor("flow-portscan", FlowPSInit);
00128 }
00129 
00130 /** 
00131  * Display what the underlying tidbits think the config is
00132  * 
00133  * @param trackerp grab the configuration info from the portscan tracker
00134  */
00135 static void FlowPSOutputConfig(PS_TRACKER *trackerp)
00136 {
00137     if(pv.quiet_flag)
00138         return;
00139 
00140     flow_printf(",-----------[flow-portscan config]-------------\n");
00141     flow_printf("| TCP Penalties:  %s\n", trackerp->config.tcp_penalties ? "On": "Off");
00142     flow_printf("|    Ouput Mode:  %s\n",
00143                 (trackerp->config.output_mode == VARIABLEMSG) ? "msg" : "pktkludge");
00144     flow_printf("|    Base Score:  %d\n", trackerp->config.base_score);
00145     
00146     flow_printf("+----------------------------------------------\n");
00147     flow_printf("| Scoreboard:  ACTIVE         PORTSCANNER\n");
00148     flow_printf("|     memcap:  %-8d         %-8d\n",
00149                 scoreboard_memcap(&trackerp->table_active),
00150                 scoreboard_memcap(&trackerp->table_scanner));
00151     flow_printf("|       rows:  %-8d         %-8d\n",
00152                 scoreboard_row_count(&trackerp->table_active),
00153                 scoreboard_row_count(&trackerp->table_scanner));
00154     flow_printf("|   overhead:  %-8d(%%%.02lf) %-8d(%%%.02lf)\n",
00155                 scoreboard_overhead_bytes(&trackerp->table_active),
00156                 calc_percent(scoreboard_overhead_bytes(&trackerp->table_active),
00157                              scoreboard_memcap(&trackerp->table_active)),
00158                 scoreboard_overhead_bytes(&trackerp->table_scanner),
00159                 calc_percent(scoreboard_overhead_bytes(&trackerp->table_scanner),
00160                              scoreboard_memcap(&trackerp->table_scanner)));
00161 
00162     flow_printf("|      fixed-size:    %-4ds        %-4ds\n",
00163                 trackerp->config.limit_talker.fixed_size,
00164                 trackerp->config.limit_scanner.fixed_size);
00165     flow_printf("|    sliding-size:    %-4ds        %-4ds\n",
00166                 trackerp->config.limit_talker.sliding_size,
00167                 trackerp->config.limit_scanner.sliding_size);
00168     flow_printf("| threshold-fixed:    %-4u         %-4u\n",
00169                 trackerp->config.limit_talker.fixed,
00170                 trackerp->config.limit_scanner.fixed);
00171     flow_printf("| threshold-sliding:  %-4u         %-4u\n",
00172                 trackerp->config.limit_talker.sliding,
00173                 trackerp->config.limit_scanner.sliding);
00174     flow_printf("|      window scale:  %-.2lf         %-.2lf\n",
00175                 trackerp->config.limit_talker.window_scale,
00176                 trackerp->config.limit_scanner.window_scale);
00177     
00178     
00179     flow_printf("+----------------------------------------------\n");
00180     flow_printf("|   Uniqueness:  memcap: %8d rows: %8d\n",
00181                ut_memcap(&trackerp->unique_tracker),
00182                ut_row_count(&trackerp->unique_tracker));
00183     flow_printf("|      overhead: %d (%%%.02lf)\n",               
00184                 ut_overhead_bytes(&trackerp->unique_tracker),
00185                 calc_percent(ut_overhead_bytes(&trackerp->unique_tracker),
00186                              ut_memcap(&trackerp->unique_tracker)));
00187     
00188     if(flowps_server_stats_enabled(trackerp) == FLOW_SUCCESS)
00189     {
00190         flow_printf("+----------------------------------------------\n");        
00191         flow_printf("| Server Stats:  memcap: %8d rows: %8d\n",
00192                     server_stats_memcap(&trackerp->server_stats),
00193                     server_stats_row_count(&trackerp->server_stats));
00194         flow_printf("|      overhead: %d (%%%.02lf)\n",               
00195                     server_stats_overhead_bytes(&trackerp->server_stats),
00196                     calc_percent(server_stats_overhead_bytes(&trackerp->server_stats),
00197                                  server_stats_memcap(&trackerp->server_stats)));
00198         flow_printf("|   learning time: %d\n",
00199                     trackerp->config.server_learning_time);
00200         flow_printf("|    ignore limit: %u\n",
00201                     trackerp->config.server_ignore_limit);
00202         flow_printf("|   scanner limit: %u\n",
00203                     trackerp->config.server_scanner_limit);
00204         
00205         
00206     }
00207     else
00208     {
00209         flow_printf("| Server Stats: Disabled\n");
00210     }
00211 
00212     flow_printf("`----------------------------------------------\n");
00213 }
00214      
00215 
00216 
00217 /** 
00218  * Initialize the configuration of the flow preprocessor
00219  * 
00220  * @param args command line arguments from snort.conf
00221  */
00222 static void FlowPSInit(u_char *args)
00223 {
00224     static int init_once = 0;    
00225     int ret;
00226 
00227     PS_TRACKER *pstp = &s_tracker;
00228     PS_CONFIG  tconfig;
00229 
00230     if(flowps_init_pkt())
00231     {
00232         flow_fatalerror("Error initializing flowps packet!\n");
00233     }
00234     
00235     if(!SppFlowIsRunning())
00236     {
00237         flow_fatalerror("%s(%d) flow-portscan requires spp_flow to be enabled!\n",
00238                         file_name, file_line);
00239     }
00240     
00241     if(init_once)
00242     {
00243         flow_fatalerror("%s(%d) Unable to reinitialize flow-portscan!\n",
00244                         file_name, file_line);
00245     }
00246     else
00247     {
00248         init_once = 1;
00249     }
00250 
00251     FlowPSSetDefaults(&tconfig);
00252 
00253     FlowPSParseArgs(&tconfig, args);
00254 
00255     
00256     if((ret = flowps_init(pstp, &tconfig)) != FLOW_SUCCESS)
00257     {
00258         flow_fatalerror("Unable to initialize the flow cache!"
00259                         "-- try more memory (current memcap is %d)\n",
00260                         tconfig.sb_memcap_total);
00261     }
00262 
00263     FlowPSOutputConfig(pstp);
00264     
00265     AddFuncToCleanExitList(FlowPSCleanExit, NULL);
00266     AddFuncToRestartList(FlowPSRestart, NULL);
00267 }
00268 
00269 
00270 static void FlowPSParseOption(PS_CONFIG *config,
00271                               char *fname, int lineno,
00272                               char *key, char *value)
00273 {
00274     int ivalue;
00275 
00276     if(!key || !value)
00277     {
00278         flow_fatalerror("%s:(%d) Invalid command line arguments!\n");
00279     }
00280 
00281     if(s_debug > 1)
00282         flow_printf("key: %s value: %s\n", key, value);
00283     
00284     if(!strcasecmp(key, "scoreboard-memcap-talker"))
00285     {
00286         ivalue = atoi(value);
00287         config->sb_memcap_talker = ivalue;
00288     }
00289     else if(!strcasecmp(key, "scoreboard-memcap-scanner"))
00290     {
00291         ivalue = atoi(value);
00292         config->sb_memcap_scanner = ivalue;
00293     }
00294     else if(!strcasecmp(key,"unique-memcap"))
00295     {
00296         ivalue = atoi(value);
00297         config->ut_memcap = ivalue;
00298     }
00299     else if(!strcasecmp(key,"server-memcap"))
00300     {
00301         ivalue = atoi(value);
00302         config->server_memcap = ivalue;
00303     }
00304     else if(!strcasecmp(key, "scoreboard-rows-talker"))
00305     {
00306         ivalue = atoi(value);
00307         config->sb_rows_talker = ivalue;
00308     }
00309     else if(!strcasecmp(key, "scoreboard-rows-scanner"))
00310     {
00311         ivalue = atoi(value);
00312         config->sb_rows_scanner = ivalue;
00313     }
00314     else if(!strcasecmp(key,"unique-rows"))
00315     {
00316         ivalue = atoi(value);
00317         config->ut_rows = ivalue;
00318     }
00319     else if(!strcasecmp(key,"server-rows"))
00320     {
00321         ivalue = atoi(value);
00322         config->server_rows = ivalue;
00323     }
00324     else if(!strcasecmp(key, "server-watchnet"))
00325     {
00326         IPSET *ipset = ipset_new(IPV4_FAMILY);
00327 
00328         if(!ipset || ip4_setparse(ipset, value) !=0)
00329         {
00330             flow_fatalerror("%s(%d) Unable to create an IPSet from %s\n",
00331                             file_name,file_line,value);
00332         }
00333 
00334         config->server_watchnet_ipv4 = ipset;        
00335     }
00336     else if(!strcasecmp(key, "src-ignore-net"))
00337     {
00338         IPSET *ipset = ipset_new(IPV4_FAMILY);
00339 
00340         if(!ipset || ip4_setparse(ipset, value) !=0)
00341         {
00342             flow_fatalerror("%s(%d) Unable to create an IPSet from %s\n",
00343                             file_name,file_line,value);
00344         }
00345 
00346         config->src_ignore_ipv4 = ipset;        
00347     }
00348     else if(!strcasecmp(key, "dst-ignore-net"))
00349     {
00350         IPSET *ipset = ipset_new(IPV4_FAMILY);
00351 
00352         if(!ipset || ip4_setparse(ipset, value) !=0)
00353         {
00354             flow_fatalerror("%s(%d) Unable to create an IPSet from %s\n",
00355                        file_name,file_line,value);
00356         }
00357 
00358         config->dst_ignore_ipv4 = ipset;        
00359     }
00360     else if(!strcasecmp(key, "tcp-penalties"))
00361     {
00362         if(toggle_option(key, value, &config->tcp_penalties))
00363         {
00364             flow_fatalerror("%s(%d) Error processing %s directive (value = %s)\n",
00365                        file_name,file_line,key,value);
00366         }
00367     }
00368     else if(!strcasecmp(key, "server-learning-time"))
00369     {
00370         ivalue = atoi(value);
00371         config->server_learning_time = ivalue;
00372     }   
00373     else if(!strcasecmp(key, "server-ignore-limit"))
00374     {
00375         ivalue = atoi(value);
00376         config->server_ignore_limit = ivalue;
00377     }
00378     else if(!strcasecmp(key, "server-scanner-limit"))
00379     {
00380         ivalue = atoi(value);
00381         config->server_scanner_limit = ivalue;
00382     }
00383     else if(!strcasecmp(key, "talker-fixed-threshold"))
00384     {
00385         ivalue = atoi(value);
00386         config->limit_talker.fixed = ivalue;
00387     }
00388     else if(!strcasecmp(key, "talker-sliding-threshold"))
00389     {
00390         ivalue = atoi(value);
00391         config->limit_talker.sliding = ivalue;
00392     }
00393     else if(!strcasecmp(key, "talker-fixed-window"))
00394     {
00395         ivalue = atoi(value);
00396         config->limit_talker.fixed_size = ivalue;
00397     }
00398     else if(!strcasecmp(key, "talker-sliding-window"))
00399     {
00400         ivalue = atoi(value);
00401         config->limit_talker.sliding_size = ivalue;
00402     }
00403     else if(!strcasecmp(key, "talker-sliding-scale-factor"))
00404     {
00405         config->limit_talker.window_scale = strtod(value, NULL);
00406     }
00407     else if(!strcasecmp(key, "scanner-fixed-threshold"))
00408     {
00409         ivalue = atoi(value);
00410         config->limit_scanner.fixed = ivalue;
00411     }
00412     else if(!strcasecmp(key, "scanner-sliding-threshold"))
00413     {
00414         ivalue = atoi(value);
00415         config->limit_scanner.sliding = ivalue;
00416     }
00417     else if(!strcasecmp(key, "scanner-fixed-window"))
00418     {
00419         ivalue = atoi(value);
00420         config->limit_scanner.fixed_size = ivalue;
00421     }
00422     else if(!strcasecmp(key, "scanner-sliding-window"))
00423     {
00424         ivalue = atoi(value);
00425         config->limit_scanner.sliding_size = ivalue;
00426     }
00427     else if(!strcasecmp(key, "scanner-sliding-scale-factor"))
00428     {
00429         config->limit_scanner.window_scale = strtod(value, NULL);
00430     }
00431     else if(!strcasecmp(key, "base-score"))
00432     {
00433         config->base_score = atoi(value);
00434     }
00435     else if(!strcasecmp(key, "dumpall"))
00436     {
00437         config->dumpall = atoi(value);
00438     }
00439     else if(!strcasecmp(key, "alert-mode"))
00440     {
00441         if(!strcasecmp(value, "once"))
00442         {
00443             config->alert_once = 1;
00444         }
00445         else if(!strcasecmp(value, "all"))
00446         {
00447             config->alert_once = 0;
00448         }
00449         else
00450         {
00451             flow_fatalerror("%s(%d) Bad option to %s => %s\n",
00452                        file_name, file_line, key, value);
00453         }
00454     }
00455     else if(!strcasecmp(key, "output-mode"))
00456     {
00457         if(!strcasecmp(value, "msg"))
00458         {
00459             config->output_mode = VARIABLEMSG;
00460         }
00461         else if(!strcasecmp(value, "pktkludge"))
00462         {
00463             config->output_mode = PKTKLUDGE;
00464         }
00465         else
00466         {
00467             flow_fatalerror("%s(%d) Bad option to %s => %s\n",
00468                        file_name, file_line, key, value);
00469         }
00470     }
00471     else        
00472     {
00473         flow_fatalerror("%s(%d) Unknown Arguments: key(%s) value(%s)\n",
00474                    fname, lineno, key, value);
00475     }
00476     
00477 }
00478 
00479 
00480 /** 
00481  * Parse out the snort.conf line
00482  *
00483  * output type - (variable alert string, custom file, pktkludge)
00484  * watch-net - optional 
00485  * ignore-net - optional
00486  *
00487  * @param config config to set
00488  * @param args string to parse
00489  */
00490 static void FlowPSParseArgs(PS_CONFIG *config , char *args)
00491 {
00492     const char *delim = " \t";
00493     char *key, *value;
00494     char *myargs;
00495     
00496     if(!config)
00497     {
00498         flow_fatalerror("FlowPSParseArgs: NULL config passed\n!");
00499     }
00500 
00501     if(!args)
00502     {
00503         return;
00504     }
00505     
00506     while(isspace((int)*args))
00507         args++;
00508 
00509     if(*args == '\0')
00510     {
00511         return;
00512     }
00513 
00514     myargs = strdup(args);
00515 
00516     if(myargs == NULL)
00517         flow_fatalerror("%s(%d) Unable to allocate memory!\n", file_name, file_line);
00518 
00519     key = strtok(myargs, delim);
00520 
00521     while(key != NULL)
00522     {
00523         value = strtok(NULL, delim);
00524 
00525         if(!value)
00526         {
00527             flow_fatalerror("%s(%d) key %s has no value", file_name, file_line); 
00528         }
00529 
00530         FlowPSParseOption(config, file_name, file_line, key, value);                
00531         key = strtok(NULL, delim);
00532     }
00533 
00534     if(myargs)
00535         free(myargs);
00536 
00537     /* is server statistics table enabled? */
00538     if(config->server_watchnet_ipv4 != NULL)
00539     {
00540         if((config->server_scanner_limit == 0) &&
00541            (config->server_ignore_limit == 0))
00542         {
00543             flow_fatalerror("A Server watchnet is set"
00544                             " with no scanner or ignore limit\n"
00545                             "Perhaps you should just remove"
00546                             " the server-watchnet option\n");
00547 
00548         }
00549             
00550     }
00551 }
00552 
00553 void FlowPSRestart(int signal, void *data)
00554 {
00555     return;
00556 }
00557 
00558 void FlowPSCleanExit(int signal, void *data)
00559 {
00560     if(s_pkt)
00561     {
00562         free(s_pkt);
00563         s_pkt = NULL;
00564     }
00565 
00566     if(!pv.quiet_flag)
00567         flowps_stats(&s_tracker);
00568 
00569     flowps_destroy(&s_tracker);
00570     return;
00571 }
00572 
00573 /**
00574  * The callback for the flow-portscan module
00575  *
00576  * This function's purpose is to do about the same thing as a
00577  * traditional snort preprocessor.  The only difference is that this
00578  * occurs only on a specific FLOW position.
00579  *
00580  * This individual callback position is only valid in the "NEW" flow
00581  * position.
00582  *
00583  * The operations are pretty much the same as laid out by
00584  *
00585  * Chris Green, Marc Norton, Dan Roelker
00586  *
00587  * Basic code flow:
00588  *
00589  * 1) Get the score and flag type
00590  * 2) return if the score is 0
00591  * 3) Get the score entry node
00592  * 4) Perform time window maintence 
00593  *    - includes flushing the "scan data" out of the subsys
00594  * 5) Process the score data
00595  * 6) Generate alerts if necessary
00596  *
00597  * @param position where in the flow module this is being called from
00598  * @param flow the flow that the stats are kept for
00599  * @param direction the direction of the flow
00600  * @param cur the current time
00601  * @param p the current packet (may be NULL)
00602  *
00603  * @return TBD
00604  */
00605 int flowps_newflow_callback(FLOW_POSITION position, FLOW *flowp,
00606                             int direction, time_t cur, FLOWPACKET *p)
00607 {
00608     TRACKER_POSITION tr_pos = TRACKER_ACTIVE; /* where new nodes get inserted */
00609     PS_TRACKER *pstp = &s_tracker;
00610     SCORE_ENTRY *current_entry = NULL;
00611     int ret, alert_flags, score;    
00612     u_int8_t cflags;
00613     u_int32_t *address = &flowp->key.init_address;
00614 
00615     if(!flowps_enabled())
00616         return 0;
00617 
00618     if(s_debug > 5)
00619     {
00620         printf("DEBUG: callback %s:%d -> %s:%d\n",
00621                inet_ntoax(p->iph->ip_src.s_addr), p->sp,
00622                inet_ntoax(p->iph->ip_dst.s_addr), p->dp);
00623     }
00624 
00625     if(position != FLOW_NEW)        
00626     {
00627 #ifndef WIN32
00628         flow_printf("Wrong callback position for %s\n", __func__);
00629 #else
00630         flow_printf("Wrong callback position for %s(%d)\n", __FILE__, __LINE__);
00631 #endif
00632         return 0;
00633     }
00634 
00635     if(flowps_is_ignored_ipv4(pstp,
00636                               &flowp->key.init_address,
00637                               &flowp->key.resp_address) == FLOW_SUCCESS)
00638     {
00639         return 0;
00640     }
00641 
00642     if(IsTcpPacket(p))
00643     {
00644         /* allow radically different flags from SYN help score
00645          * differently */
00646         cflags = GetTcpFlags(p);
00647     }
00648     else
00649     {
00650         cflags = 0;
00651     }
00652 
00653     /*
00654      * if we can't find the score for whatever reason, or the
00655      * resultant score is 0 (indicating that this a "normal" event),
00656      * just go ahead and return 
00657      */
00658     if(flowps_get_score(pstp, flowp, cur,
00659                         cflags, &score, &tr_pos) != FLOW_SUCCESS)
00660     {
00661         return -1;
00662     }
00663 
00664     if(score == 0)
00665     {
00666         return 0;
00667     }
00668     else if(s_debug > 5)
00669     {
00670         flow_printf("new unique flow!\n");
00671         flowkey_print(&flowp->key);
00672         flow_printf("\n");
00673     }
00674     
00675     /* run the "score entry finder" or create a new node */    
00676     ret = flowps_find_entry(pstp, address, &current_entry);
00677 
00678     if(ret == FLOW_NOTFOUND)
00679     {
00680         ret = flowps_add_entry(pstp,  tr_pos, address, &current_entry);
00681 
00682         if(ret != FLOW_SUCCESS)            
00683         {
00684             /* tracker failed horribly */
00685 #ifndef WIN32
00686             flow_printf("flowps_add_entry check failed in %s\n", __func__);
00687 #else
00688             flow_printf("flowps_add_entry check failed in %s(%d)\n", __FILE__, __LINE__);
00689 #endif
00690             return 0;
00691         }
00692     }
00693     else if(ret != FLOW_SUCCESS)
00694     {
00695 #ifndef WIN32
00696         flow_printf("bad return for finding the entry %s\n", __func__);
00697 #else
00698         flow_printf("bad return for finding the entry %s(%d)\n", __FILE__, __LINE__);
00699 #endif
00700         return 0;
00701     }
00702 
00703     flowps_sliding_winadj(&current_entry->sliding_talker,
00704                           cur,
00705                           &pstp->config.limit_talker);
00706 
00707     flowps_fixed_winadj(&current_entry->fixed_talker,
00708                         cur,
00709                         &pstp->config.limit_talker);
00710 
00711     flowps_sliding_winadj(&current_entry->sliding_scanner,
00712                           cur,
00713                           &pstp->config.limit_scanner);
00714 
00715     flowps_fixed_winadj(&current_entry->fixed_scanner,
00716                         cur,
00717                         &pstp->config.limit_scanner);
00718 
00719     /* maintain the list of recent connections */
00720     flowps_set_last_address(current_entry, flowp, cflags);
00721 
00722     /* windows adjusted, lets get us some alerts */
00723     if(s_debug > 5 && score > 1)
00724     {
00725         flow_printf("XXXX **** got a big old score(%d) because of [%s] -> %s\n",
00726                score,  mktcpflag_str(cflags),
00727                inet_ntoa(*(struct in_addr *) (&flowp->key.resp_address)));
00728         flowps_entry_print(current_entry, address);
00729         flow_printf("\nXXXX ****\n");
00730     }
00731 
00732     if(flowps_score_entry(pstp, current_entry, score, tr_pos, 
00733                           pstp->config.alert_once,
00734                           &alert_flags) != FLOW_SUCCESS)
00735     {
00736 #ifndef WIN32
00737         flow_printf("bad return for finding the entry %s\n", __func__);
00738 #else
00739         flow_printf("bad return for finding the entry %s(%d)\n", __FILE__, __LINE__);
00740 #endif
00741         return 0;
00742     }
00743 
00744     /* If someone generates an event 
00745      * 
00746      *
00747      */
00748     if(current_entry->position == TRACKER_ACTIVE && tr_pos == TRACKER_SCANNER)
00749     {
00750         int ret;
00751 
00752         
00753         //flow_printf("moving this one! (cur %d) -> (new %d) %s\n",
00754         //current_entry->position, tr_pos, inet_ntoa(*(struct in_addr *) address));
00755 
00756         /* move address TO scanner FROM active */
00757         ret = scoreboard_move(&pstp->table_scanner, &pstp->table_active, address);
00758         
00759         if(ret != FLOW_SUCCESS)
00760         {
00761             flow_printf("Unable to move %s\n",inet_ntoa(*(struct in_addr *) address));
00762             return -1;
00763         }
00764         else
00765         {
00766             /* @todo - move this into the scoreboard mv call */
00767             current_entry->position = TRACKER_SCANNER;
00768         }
00769        
00770     }
00771 
00772     if(s_debug > 5)
00773     {
00774         if(tr_pos == TRACKER_SCANNER)
00775         {
00776             flow_printf("Found a tracker scanner!\n");
00777             flowps_entry_print(current_entry, address);
00778         }
00779     }
00780     
00781     if(s_debug > 10)
00782     {
00783         flowps_entry_print(current_entry, address);
00784     }
00785     
00786     if(alert_flags)        
00787     {
00788         /*
00789         **  We OR the alert_flags here because we only want to add
00790         **  new alerts and reset alerts that might not be set in
00791         **  alert_flags.  This is for the case of alert_once being
00792         **  set.
00793         */
00794         current_entry->flags |= alert_flags;
00795             
00796         /* push things through the output system */
00797         
00798         flowps_generate_flow_event(current_entry, p, address,
00799                                    pstp->config.output_mode, cur);
00800     }
00801 
00802     return 0;
00803 }
00804 
00805 static int flowps_generate_flow_event(SCORE_ENTRY *sep, FLOWPACKET *orig_packet,
00806                                       u_int32_t *address,
00807                                       FLOWPS_OUTPUT output_type,
00808                                       time_t cur)
00809 {
00810     Packet *p = NULL;
00811     char buf[1024 + 1];    
00812     u_int32_t event_id; 
00813     u_int32_t event_type; /* the sid for the gid */
00814     /*  Assign an event type to the display
00815      */
00816     if(sep->flags & ALERT_FIXED_SCANNER)
00817     {
00818         event_type = FLOW_SCANNER_FIXED_ALERT;
00819     }
00820     else if(sep->flags & ALERT_SLIDING_SCANNER)
00821     {
00822         event_type = FLOW_SCANNER_SLIDING_ALERT;
00823     }
00824     else if(sep->flags & ALERT_SLIDING_TALKER)
00825     {
00826         event_type = FLOW_TALKER_SLIDING_ALERT;
00827     }
00828     else if(sep->flags & ALERT_FIXED_TALKER)
00829     {
00830         event_type = FLOW_TALKER_FIXED_ALERT;
00831     }
00832     else
00833     {
00834         return FLOW_EINVALID;
00835     }
00836     
00837     switch(output_type)
00838     {
00839     case PKTKLUDGE:
00840         /* log a packet to the output system */
00841         p = flowps_mkpacket(sep, orig_packet, address, cur);      
00842     case VARIABLEMSG:
00843         snprintf(buf, 1024,
00844                  "Portscan detected from %s Talker(fixed: %u sliding: %u) Scanner(fixed: %u sliding: %u)",
00845                  inet_ntoa(*(struct in_addr *) address),
00846                  sep->fixed_talker.score, sep->sliding_talker.score,
00847                  sep->fixed_scanner.score, sep->sliding_scanner.score);
00848         buf[1024] = '\0';
00849         
00850         /* p is NULL w/ the VARIABLEMSG fmt */
00851         event_id = GenerateSnortEvent(p,
00852                                       GENERATOR_FLOW_PORTSCAN,
00853                                       event_type,
00854                                       1, /* revision */
00855                                       1, /* classification */
00856                                       2, /* medium priority */
00857                                       buf);
00858         /*
00859          *  If this is the first time we have called an alert on this
00860          *  function, save it off so we have an event reference.
00861          *
00862          *  DEPRECATED:
00863          *    The event_id was to tag additional events to a previous
00864          *    one, but that logic was ifdef'ed out, so we'll keep it
00865          *    around anyway.
00866          */
00867         sep->event_id = event_id;
00868 
00869         /*
00870          * this is the last tv_sec from the packet
00871          */
00872         sep->event_sec = packet_timeofday(); 
00873     }
00874     
00875     return FLOW_SUCCESS;
00876 }
00877 
00878 /** 
00879  * Print the score entry to a buffer
00880  *
00881  * snprintf doesn't protect us any since we are calculating so much
00882  * but it does make me be explicit on how much data I am putting in.
00883  * 
00884  * @param buf buf to print into
00885  * @param buflen size of buffer
00886  * @param sep score entry to print
00887  * @param address address of attacker
00888  * 
00889  * @return 0 on sucess
00890  */
00891 static int score_entry_sprint(unsigned char *buf, int buflen, SCORE_ENTRY *sep, u_int32_t *address)
00892 {
00893     int printed = 0; /* tmp */
00894     int total_printed = 0;
00895     int remaining = buflen;
00896     int i;
00897     
00898     if(buf && buflen > 0 && sep && address)
00899     {
00900         printed = snprintf(buf + total_printed,
00901                            remaining,
00902                            "Address: %s\n"
00903                            "AT_SCORE: %u\n"
00904                            "ST_SCORE: %u\n"
00905                            "AS_SCORE: %u\n"
00906                            "SS_SCORE: %u\n"
00907                            "Total Connections: %u\n"
00908                            "ScanFlags: 0x%x\n"
00909                            "AT_STARTEND: %u %u\n"
00910                            "ST_STARTEND: %u %u\n"
00911                            "AS_STARTEND: %u %u\n"
00912                            "SS_STARTEND: %u %u\n"
00913                            "REF_SEC:   %u\n"
00914                            "REF_EVENT: %u\n",
00915                            inet_ntoa(*(struct in_addr *)address),
00916                            sep->fixed_talker.score,
00917                            sep->sliding_talker.score,
00918                            sep->fixed_scanner.score,
00919                            sep->sliding_scanner.score,
00920                            sep->connections_seen,
00921                            sep->flags,
00922                            (unsigned) sep->fixed_talker.start,
00923                            (unsigned) sep->fixed_talker.ends,
00924                            (unsigned) sep->sliding_talker.start,
00925                            (unsigned) sep->sliding_talker.ends,
00926                            (unsigned) sep->fixed_scanner.start,
00927                            (unsigned) sep->fixed_scanner.ends,
00928                            (unsigned) sep->sliding_scanner.start,
00929                            (unsigned) sep->sliding_scanner.ends,
00930                            (unsigned) sep->event_sec,
00931                            sep->event_id);
00932 
00933         if(printed <= 0)
00934             return -1;
00935 
00936         remaining     -= printed;
00937         total_printed += printed;
00938         
00939         if(remaining <= 0)            
00940             return -1;
00941 
00942         /* as long as we have a postive # of connections, pump out the info */
00943         for(i=0; i < sep->connections_seen && i < FLOWPS_HOSTS_SIZE; i++)
00944         {
00945             CONN_ENTRY *cp = &sep->last_hosts[i];
00946 
00947             
00948             printed = snprintf(buf + total_printed,
00949                                remaining,
00950                                "ConnInfo: (%d:%s:%d Flags: %x)\n",
00951                                cp->protocol,
00952                                inet_ntoa(*(struct in_addr*) &cp->ip),
00953                                cp->port,
00954                                cp->cflags);
00955 
00956             if(printed <= 0)
00957                 return -1;
00958             remaining     -= printed;
00959             total_printed += printed;
00960             if(remaining <= 0)            
00961                 return -1;
00962         }
00963 
00964         /* successful exit! */
00965         return total_printed;        
00966     }
00967     
00968     return -1;
00969 }
00970 
00971 /** 
00972  * Make a packet with the flowps data in it.
00973  *
00974  * This is used to generate a fake IP datagram to carry portscan data
00975  * from snort so that it can be processed by custom utilities.
00976  *
00977  * SRC + DST mac addresses = "MACDAD"
00978  * sip+dip == attacker 
00979  * ip proto 255
00980  * ttl = 0
00981  * chksum = 0
00982  *
00983  * @param sep score entry to generate a packet from
00984  * @param address ptr to the address of the attacker
00985  * 
00986  * @return a pointer to a fully formed packet on success
00987  */
00988 static Packet *flowps_mkpacket(SCORE_ENTRY *sep, FLOWPACKET *orig_packet, u_int32_t *address, time_t cur)
00989 {
00990     Packet *p = s_pkt;
00991     int len;
00992     u_int32_t dst_ip;
00993     unsigned short plen;
00994 
00995     p->pkth->ts.tv_sec = cur;
00996 
00997 
00998     dst_ip = GetIPv4DstIp(orig_packet);
00999 
01000     memcpy(&p->iph->ip_src.s_addr, address, 4);
01001     memcpy(&p->iph->ip_dst.s_addr, &dst_ip, 4);
01002 
01003     len = score_entry_sprint(p->data, FLOWPSMAXPKTSIZE, sep, address);
01004     
01005     if(len <= 0)
01006     {
01007         /* this can never return more than FLOWPSMAXPKTSIZE */
01008         return NULL;
01009     }
01010 
01011     p->data[len] = '\0';
01012     
01013     /* explicitly cast it down */
01014     plen = (len & 0xFFFF);
01015 
01016     if((plen + IP_HEADER_LEN) < plen)
01017     {
01018         /* wrap around */
01019         return NULL;
01020     }
01021         
01022     p->dsize = plen;
01023     
01024     plen += IP_HEADER_LEN;
01025     p->iph->ip_len = htons(plen);
01026 
01027     p->pkth->caplen = ETHERNET_HEADER_LEN + plen;
01028     p->pkth->len    = ETHERNET_HEADER_LEN + plen;
01029         
01030     return p;
01031 }
01032 
01033 /** 
01034  * Initialize the static packet used for the portscan flow plugin.
01035  *
01036  * This allocates 2 bytes over what it needs to so that the IP header
01037  * will be 32bit aligned. 
01038  * 
01039  * @return FLOW_SUCCESS on sucess
01040  */
01041 static int flowps_init_pkt(void)     
01042 {
01043     Packet *p = NULL;
01044     const char *flow_portscan_mac_addr = "MACDADDY";
01045     const char twiddlebytes = 2;
01046 
01047     p = calloc(1,sizeof(Packet));
01048 
01049     if(!p)
01050     {
01051         flow_fatalerror("Unable to alloc memory for the flow-portscan packet!\n");
01052     }
01053 
01054     p->pkth = calloc(1,
01055                      sizeof(struct pcap_pkthdr) + ETHERNET_HEADER_LEN
01056                      + twiddlebytes + IP_MAXPACKET);
01057 
01058     if(!p->pkth)
01059     {
01060         flow_fatalerror("Unable to alloc memory for the flow-portscan packet!\n");
01061     }
01062     else
01063     {
01064         p->pkth = (struct pcap_pkthdr *) (((u_int8_t *) p->pkth) + twiddlebytes);
01065     }
01066 
01067     p->pkt  =  ((u_int8_t *)p->pkth) + sizeof(SnortPktHeader);
01068     p->eh   =   (EtherHdr *)((u_int8_t *)p->pkt);
01069     p->iph  =  (IPHdr *)((u_int8_t *)p->eh + ETHERNET_HEADER_LEN);
01070     p->data =  ((u_int8_t *)p->iph) + sizeof(IPHdr);
01071     
01072     /* p->data is now pkt +
01073      *  IPMAX_PACKET - (IP_HEADER_LEN + ETHERNET_HEADER_LEN)
01074      *
01075      * This is MAXFLOWPSPKTSIZE
01076      *
01077      */
01078 
01079     p->eh->ether_type = htons(0x0800);
01080     memcpy(p->eh->ether_dst, flow_portscan_mac_addr, 6);
01081     memcpy(p->eh->ether_src, flow_portscan_mac_addr, 6);
01082     
01083     SET_IP_VER(p->iph,  0x4);
01084     SET_IP_HLEN(p->iph, 0x5);
01085     
01086     p->iph->ip_proto = 0xFF;  /* set a reserved protocol */
01087     p->iph->ip_ttl   = 0x00;  /* set a TTL we'd never see */
01088     p->iph->ip_len = 0x5;
01089     p->iph->ip_tos = 0x10;
01090 
01091     /* save off s_pkt for flowps_mkpkt */
01092     s_pkt = p;
01093 
01094     return FLOW_SUCCESS;
01095 }

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