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

flowps.c

Go to the documentation of this file.
00001 /* $Id: */
00002 
00003 #ifdef HAVE_CONFIG_H
00004 #include "config.h"
00005 #endif
00006 
00007 
00008 #include "flowps.h"
00009 #include "scoreboard.h"
00010 #include "unique_tracker.h"
00011 #include "server_stats.h"
00012 #include "packet_time.h"
00013 #include "util_net.h"
00014 
00015 /* local copy of these tcp flags */
00016 #ifndef TH_FIN
00017 
00018 #define TH_FIN  0x01
00019 #define TH_SYN  0x02
00020 #define TH_RST  0x04
00021 #define TH_PUSH 0x08
00022 #define TH_ACK  0x10
00023 #define TH_URG  0x20
00024 #define TH_RES2 0x40
00025 #define TH_RES1 0x80
00026 
00027 
00028 #endif /* TH_FIN */
00029 
00030 #define FLOWPS_NC 1000000 /* number of rows to use for each scan table */
00031 
00032 static int s_debug = 0;
00033 static int s_enabled = 0;
00034 
00035 /** 
00036  * Setup a SCORE_THRESHOLD object.
00037  *
00038  * This contains the limits and window sizes that will be used each
00039  * time we evaluate a SCORE_ENTRY from one of the scoreboards.
00040  * 
00041  * @param thr pointer to the threshold to initialize
00042  * @param fixed_size the time window for fixed scale
00043  * @param fixed_limit the score limit to alert on
00044  * @param sliding_size the sliding time window initial size
00045  * @param sliding_limit score limit to alert on
00046  * @param window_scale what to multiple the sliding size on each "hit"
00047  * 
00048  * @return FLOW_SUCCESS on success
00049  */
00050 int flowps_mkthreshold(SCORE_THRESHOLD *thr,
00051                        int fixed_size, u_int32_t fixed_limit,
00052                        int sliding_size, u_int32_t sliding_limit,
00053                        float window_scale)
00054 {
00055     if(!thr)
00056         return FLOW_ENULL;
00057     
00058     if(fixed_size < 0)
00059         fixed_size = 0;
00060 
00061     if(sliding_size < 0)
00062         sliding_size = 0;
00063     
00064     thr->fixed_size   = fixed_size;
00065     thr->sliding_size = sliding_size;
00066     thr->window_scale = window_scale;
00067     thr->fixed        = fixed_limit;
00068     thr->sliding      = sliding_limit;
00069 
00070     return FLOW_SUCCESS;
00071 }
00072 
00073 /** 
00074  * Initialize the configuration structure and set everything to 0
00075  * 
00076  * @param configp config to set
00077  * 
00078  * @return FLOW_SUCCESS on success
00079  */
00080 int flowps_mkconfig(PS_CONFIG *configp,
00081                     int sb_memcap_talker,
00082                     int sb_rows_talker,
00083                     int sb_memcap_scanner,
00084                     int sb_rows_scanner,
00085                     int ut_memcap,
00086                     int ut_rows,
00087                     int server_memcap,
00088                     int server_rows,
00089                     int server_learning_time,
00090                     int tcp_penalties,
00091                     u_int32_t server_ignore_limit,
00092                     u_int32_t server_scanner_limit,
00093                     int base_score,
00094                     int alert_once,
00095                     FLOWPS_OUTPUT output_mode)
00096 {
00097     if(!configp)
00098         return FLOW_ENULL;
00099 
00100     memset(configp, 0, sizeof(PS_CONFIG));
00101            
00102     configp->sb_memcap_total   = sb_memcap_scanner + sb_memcap_talker;
00103     configp->sb_memcap_scanner = sb_memcap_scanner;
00104     configp->sb_memcap_talker  = sb_memcap_talker;
00105 
00106     configp->sb_rows_talker    = sb_rows_talker;
00107     configp->sb_rows_scanner   = sb_rows_scanner;
00108         
00109     configp->tcp_penalties = tcp_penalties;
00110 
00111     configp->ut_memcap            = ut_memcap;
00112     configp->ut_rows              = ut_rows;
00113 
00114     
00115     configp->server_memcap        = server_memcap;
00116     configp->server_rows          = server_rows;
00117     configp->server_learning_time = server_learning_time;
00118     configp->server_ignore_limit  = server_ignore_limit;
00119     configp->server_scanner_limit = server_scanner_limit;
00120     configp->base_score           = base_score;
00121     configp->alert_once           = alert_once;
00122     configp->output_mode          = output_mode;
00123     configp->dumpall              = 0;
00124     return FLOW_SUCCESS;
00125 }
00126 
00127 /** 
00128  * Determine if the server stats feature is enabled
00129  * 
00130  * @param trackerp portscan tracker
00131  * 
00132  * @return FLOW_SUCCESS if server_stats is enabled
00133  */
00134 int flowps_server_stats_enabled(PS_TRACKER *trackerp)
00135 {
00136     if(trackerp->config.server_watchnet_ipv4)
00137         return FLOW_SUCCESS;
00138     
00139     return FLOW_DISABLED;
00140 
00141 }
00142 /** 
00143  * Determine if server stats is enabled for this particular IP
00144  * address.
00145  * 
00146  * @param trackerp portscan tracker to inquire
00147  * 
00148  * @return FLOW_SUCCESS if the server watchnet stuff is enabled
00149  */
00150 int flowps_server_watch(PS_TRACKER *trackerp, u_int32_t address)
00151 {
00152     FLOWASSERT(trackerp != NULL);
00153         
00154     if(trackerp->config.server_watchnet_ipv4 == NULL)
00155         return FLOW_DISABLED;
00156 
00157     if(server_stats_contains(&trackerp->server_stats,address) == FLOW_SUCCESS)
00158         return FLOW_SUCCESS;
00159 
00160     /* finally fail */
00161     return FLOW_DISABLED;
00162 }
00163 
00164 /** 
00165  * initialize the Portscan Tracker.
00166  *
00167  * This takes several arguments, all, on the PS_CONFIG structure.
00168  * 
00169  * @param trackerp tracker object to initialize
00170  * @param configp well-formed configuration to initialize this object
00171  * 
00172  * @return FLOW_SUCCESS on success
00173  */
00174 int flowps_init(PS_TRACKER *trackerp, PS_CONFIG *configp)
00175 {
00176     int ret;
00177     
00178     if(!trackerp || !configp)
00179         return FLOW_ENULL;
00180 
00181     /* we should validate this threshold object somewhat */
00182     memcpy(&trackerp->config, configp, sizeof(PS_CONFIG));    
00183 
00184     ret = scoreboard_init(&trackerp->table_active,            /* table */
00185                           "Active Talkers",                   /* description */
00186                           TRACKER_ACTIVE,                     /* position */
00187                           trackerp->config.sb_rows_talker,    /* node count */
00188                           trackerp->config.sb_memcap_talker); /* memcap */
00189 
00190     if(ret != FLOW_SUCCESS)
00191     {
00192         return ret;
00193     }
00194     
00195     ret = scoreboard_init(&trackerp->table_scanner,            /* table */
00196                           "Portscanners",                      /* description */
00197                           TRACKER_SCANNER,                     /* position */
00198                           trackerp->config.sb_rows_scanner,    /* node count */
00199                           trackerp->config.sb_memcap_scanner); /* memcap */
00200 
00201     if(ret != FLOW_SUCCESS)
00202     {
00203         scoreboard_destroy(&trackerp->table_active);
00204         return ret;
00205     }
00206 
00207     /* setup the unique talkers table */
00208     ret = ut_init(&trackerp->unique_tracker,trackerp->config.ut_rows, trackerp->config.ut_memcap);
00209 
00210     if(ret != FLOW_SUCCESS)
00211     {
00212         scoreboard_destroy(&trackerp->table_active);
00213         scoreboard_destroy(&trackerp->table_scanner);
00214         return ret;
00215     }
00216 
00217     /* the watchnet stuff is optional */
00218     if(flowps_server_stats_enabled(trackerp) == FLOW_SUCCESS)
00219     {
00220         ret = server_stats_init(&trackerp->server_stats,
00221                                 trackerp->config.server_watchnet_ipv4,
00222                                 trackerp->config.server_rows,
00223                                 trackerp->config.server_memcap);
00224 
00225         if(ret != FLOW_SUCCESS)
00226         {
00227             scoreboard_destroy(&trackerp->table_active);
00228             scoreboard_destroy(&trackerp->table_scanner);
00229             ut_destroy(&trackerp->unique_tracker);
00230             return ret;
00231         }
00232     }    
00233 
00234     s_enabled = 1;
00235     
00236     return FLOW_SUCCESS;
00237 }
00238 
00239 int flowps_destroy(PS_TRACKER *trackerp)
00240 {
00241     if(!trackerp)
00242         return FLOW_ENULL;
00243 
00244     scoreboard_destroy(&trackerp->table_scanner);
00245     scoreboard_destroy(&trackerp->table_active);
00246     ut_destroy(&trackerp->unique_tracker);
00247     
00248     return FLOW_SUCCESS;
00249 }
00250 
00251 /** 
00252  * Reset a single flag in the alert_flags entry if the score is 0
00253  * 
00254  * @param type flag to reset
00255  * @param alert_flags flag entry
00256  * @param score score to reset
00257  */
00258 static INLINE void flowps_reset_alert_flags(u_int32_t type,
00259                                             u_int32_t *alert_flags,
00260                                             u_int32_t *score)
00261 {
00262     if(((*alert_flags) & type))
00263     {
00264         *alert_flags &= ~type;
00265         *score = 0;
00266     }
00267 }
00268 
00269 /** 
00270  * Evaluate the score on an entry, generating alerts if needed.
00271  * 
00272  * @param pstp portscan tracker
00273  * @param sep score entry 
00274  * @param score score determined for this flow
00275  * @param tr_pos what type of connection the current one is
00276  * @param alert_once alert only on the first one we find
00277  * @param alert_flags what type of alerts should we generate
00278  * 
00279  * @return FLOW_SUCCESS on success
00280  */
00281 int flowps_score_entry(PS_TRACKER *pstp, SCORE_ENTRY *sep, int score,
00282                        TRACKER_POSITION tr_pos,
00283                        int alert_once,
00284                        u_int32_t *alert_flags)
00285 {
00286     /* @todo - evaluate the score for the node before we evaluate the
00287        expiration on a sliding time window */
00288     if(!pstp || !sep || !alert_flags)
00289     {
00290         return FLOW_ENULL;
00291     }
00292 
00293     *alert_flags = 0;
00294 
00295     if(alert_once == 0)
00296     {
00297         /* if our score entry flags ever get set to 0, reset the alert
00298          * flags */
00299         flowps_reset_alert_flags(ALERT_FIXED_TALKER,
00300                                  &sep->flags,
00301                                  &sep->fixed_talker.score);
00302 
00303         flowps_reset_alert_flags(ALERT_SLIDING_TALKER,
00304                                  &sep->flags,
00305                                  &sep->sliding_talker.score);
00306 
00307         flowps_reset_alert_flags(ALERT_FIXED_SCANNER,
00308                                  &sep->flags,
00309                                  &sep->fixed_scanner.score);
00310         
00311         flowps_reset_alert_flags(ALERT_SLIDING_SCANNER,
00312                                  &sep->flags,
00313                                  &sep->sliding_scanner.score);
00314     }
00315 
00316     FLOWASSERT((tr_pos == TRACKER_SCANNER) || (tr_pos == TRACKER_ACTIVE));
00317     
00318     switch(tr_pos)
00319     {
00320     case TRACKER_SCANNER:
00321         sep->fixed_scanner.score   += score;
00322         sep->sliding_scanner.score += score;
00323         /* talking thresholds increment even if this is a "scanner"
00324          * connection */
00325         break;
00326     case TRACKER_ACTIVE:
00327         sep->fixed_talker.score    += score;
00328         sep->sliding_talker.score  += score;
00329         break;
00330     }
00331 
00332     /* done resetting the scores, now check the thresholds */   
00333     if(pstp->config.limit_talker.fixed &&
00334        pstp->config.limit_talker.fixed <= sep->fixed_talker.score)
00335     {
00336             *alert_flags |= ALERT_FIXED_TALKER;
00337     }
00338 
00339     if(pstp->config.limit_talker.sliding &&
00340        pstp->config.limit_talker.sliding <= sep->sliding_talker.score)
00341     {
00342             *alert_flags |= ALERT_SLIDING_TALKER;
00343     }
00344     
00345     if(pstp->config.limit_scanner.fixed &&
00346        pstp->config.limit_scanner.fixed <= sep->fixed_scanner.score)
00347     {
00348             *alert_flags |= ALERT_FIXED_SCANNER;
00349     }
00350 
00351     if(pstp->config.limit_scanner.sliding &&
00352        pstp->config.limit_scanner.sliding <= sep->sliding_scanner.score)
00353     {
00354             *alert_flags |= ALERT_SLIDING_SCANNER;
00355     }
00356 
00357     /*
00358     **  This logic will only give us alerts for the ones that have not
00359     **  already gone off for this score entry.
00360     */
00361     if(alert_once)
00362     {
00363         *alert_flags &= ~sep->flags;
00364     }
00365 
00366     return FLOW_SUCCESS;    
00367 }
00368 
00369 
00370 /** 
00371  * find the trackers in the table
00372  *
00373  * Currently, it first looks it up in the active table and then the
00374  * scanner table
00375  * 
00376  * @param trackerp tracker to search
00377  * @param address key to search for
00378  * @param sepp where to place the results
00379  * 
00380  * @return FLOW_SUCCESS on sucess and sets sepp
00381  */
00382 int flowps_find_entry(PS_TRACKER *trackerp, u_int32_t *address, SCORE_ENTRY **sepp)
00383 {
00384     int ret;
00385     
00386     if(!trackerp || !sepp || !address)
00387     {
00388         return FLOW_ENULL;
00389     }
00390 
00391     ret = scoreboard_find(&trackerp->table_active, address, sepp);
00392     
00393     if(ret == FLOW_NOTFOUND)
00394     {
00395         // flow_printf(stdout, "address was not found :(");
00396         /* the find failed -- look it up in the
00397          * scanner table */
00398         ret = scoreboard_find(&trackerp->table_scanner, address, sepp);
00399     }
00400 
00401     return ret;
00402 }
00403 
00404 
00405 /** 
00406  * Register a new node in the portscan tracker.
00407  *
00408  * This does not enforce that a node can only be in one table at a
00409  * time to avoid the 2 extra searching operations.  All uses of this
00410  * should be done after performing a find to make sure the trackers
00411  * do not already exist.
00412  * 
00413  * @param trackerp portscan tracker 
00414  * @param position where to place this node
00415  * @param address the address for the key
00416  * @param sepp score entry return information
00417  * 
00418  * @return FLOW_SUCCESS on success
00419  *
00420  * @retval FLOW_ENULL null arguments passed
00421  * @retval FLOW_SUCESS sucessfull added
00422  * @retval FLOW_EINVALID already in table
00423  * @retval FLOW_ENOMEM out of memory
00424  */
00425 
00426 int flowps_add_entry(PS_TRACKER *trackerp,
00427                       TRACKER_POSITION position,
00428                       u_int32_t *address,
00429                       SCORE_ENTRY **sepp)
00430 {
00431     int ret;
00432     
00433     if(position == TRACKER_ACTIVE)
00434     {
00435         ret = scoreboard_add(&trackerp->table_active, address, sepp);
00436     }
00437     else
00438     {
00439         ret = scoreboard_add(&trackerp->table_scanner, address, sepp);
00440     }
00441 
00442     if(ret == FLOW_SUCCESS)
00443     {
00444         (*sepp)->position = position;
00445     }
00446         
00447     return ret;
00448 }
00449 
00450 
00451 /** 
00452  * Printout a score entry
00453  * 
00454  * @param ps_score score entry to printf
00455  * 
00456  * @return FLOW_SUCCESS on success
00457  */
00458 int flowps_score_print(PS_SCORE *ps_score)
00459 {
00460     flow_printf(" score: %u start: %u end: %u",
00461                 ps_score->score,
00462                 (unsigned int) ps_score->start,
00463                 (unsigned int) ps_score->ends);
00464     
00465     return FLOW_SUCCESS;
00466 }
00467 
00468 
00469 int flowps_entry_print(SCORE_ENTRY *entry, u_int32_t *address)
00470 {
00471     char *c_position = "TRACKER_ACTIVE";
00472     u_int32_t i;
00473     if(entry->position == TRACKER_SCANNER)
00474         c_position = "TRACKER_SCANNER";
00475 
00476     flow_printf(",-----------------------------------------------------\n");
00477     flow_printf("| Score entry for %s@%p Flags: %x\n",
00478             inet_ntoa(*(struct in_addr *) address), entry, entry->flags);
00479 
00480 
00481     flow_printf("|   Alerts: FT: %u ST: %u FS: %u SS: %u",
00482             (entry->flags & ALERT_FIXED_TALKER),
00483             (entry->flags & ALERT_SLIDING_TALKER),
00484             (entry->flags & ALERT_FIXED_SCANNER),
00485             (entry->flags & ALERT_SLIDING_SCANNER));
00486     
00487     flowps_score_print(&entry->fixed_talker);
00488     
00489     flow_printf("\n| Position: %s\n", c_position);
00490     flow_printf("|   Fixed Talker:");
00491     flowps_score_print(&entry->fixed_talker);
00492     
00493     flow_printf("\n| Sliding Talker:");
00494     flowps_score_print(&entry->sliding_talker);
00495     
00496     flow_printf("\n|   Fixed Scanner:");
00497     flowps_score_print(&entry->fixed_scanner);
00498 
00499     flow_printf("\n| Sliding Scanner:");
00500     flowps_score_print(&entry->sliding_scanner);
00501 
00502     flow_printf("\n| Connections Seen: %u", entry->connections_seen);
00503 
00504     /* as long as we have a postive # of connections, pump out the info */
00505     for(i=0; i < entry->connections_seen && i < FLOWPS_HOSTS_SIZE; i++)
00506     {
00507         CONN_ENTRY *cp = &entry->last_hosts[i];
00508         if(cp->protocol == 6)
00509         {
00510             flow_printf("\n|        proto: %d %s:%d th_flags: %s",
00511                         cp->protocol,
00512                         inet_ntoa(*(struct in_addr*) &cp->ip),
00513                         cp->port,
00514                         mktcpflag_str(cp->cflags));
00515         }
00516         else
00517         {
00518             flow_printf("\n|        proto: %d %s:%d cflags: %d",
00519                         cp->protocol,
00520                         inet_ntoa(*(struct in_addr*) &cp->ip),
00521                         cp->port,
00522                         cp->cflags);
00523 
00524         }
00525     }
00526     flow_printf("\n`----------------------------------------------------\n");
00527 
00528     return 0;
00529 }
00530 
00531 void flowps_stats(PS_TRACKER *pstp)
00532 {
00533     int dumpall = pstp->config.dumpall;
00534         
00535     flow_printf("+---[ Flow-portscan Stats ]----------------+\n");
00536     scoreboard_stats(&pstp->table_active, dumpall);
00537     scoreboard_stats(&pstp->table_scanner, dumpall);
00538     ut_stats(&pstp->unique_tracker, dumpall);
00539     server_stats(&pstp->server_stats, dumpall);
00540 }
00541 
00542 
00543 /** 
00544  * Assign TCP penalty points
00545  *
00546  * have an optional penalty for odd flags combinations on TCP --
00547  * this should probably promote people to the TRACKER_SCANNER
00548  * table as well.
00549  *
00550  * Perhaps we should extend this to non-common ICMP errors as
00551  * well.
00552  *
00553  * S,12 & SYN are the 1 ptrs.
00554  *
00555  * XMAS w/ ACK is a 5 ptr
00556  *
00557  * SF+ is a 3 ptr.
00558  *
00559  * @param flags th_flags
00560  * @param base_score base score value for normal initiations
00561  * @param score ptr for return value 
00562  */
00563 static INLINE void flowps_tcp_penalty(u_int32_t flags, int base_score, int *score)
00564 {
00565     if((flags == TH_SYN) || (flags == (TH_SYN|TH_RES1|TH_RES2)))
00566     {
00567         /* this is the common case for a session initiator */
00568         *score = base_score;
00569     }
00570     else if((flags & (TH_SYN|TH_FIN|TH_ACK)) == (TH_SYN|TH_FIN|TH_ACK))
00571     {
00572         *score = 5;
00573     }
00574     else if((flags & (TH_SYN|TH_FIN)) == (TH_SYN|TH_FIN))
00575     {
00576         *score = 3;
00577     }
00578     else
00579     {
00580         *score = 2;
00581     }
00582 }
00583      
00584 
00585 /** 
00586  * Get the score and the type of connection this is
00587  *
00588  * If the score is 0, this is an already existing connection and can
00589  * be successfully ignored.
00590  *
00591  * @param pstp portscan tracker
00592  * @param flowp flow to aquire a score for *
00593  * @param cur current time
00594  * @flags packet related flags that can be used to modify the score
00595  * @param score return value for the score
00596  * @param type return value for the type of connection
00597  * 
00598  * @return FLOW_SUCCESS on success and sets the score and type
00599  */
00600 int flowps_get_score(PS_TRACKER *pstp, FLOW *flowp,
00601                      time_t cur, u_int32_t flags,
00602                      int *score, TRACKER_POSITION *type)
00603 {
00604     UT_TYPE unique;
00605     u_int32_t hitcount = 1;
00606     int base_score;
00607     
00608     
00609     if(!flowp || !score || !type)
00610     {
00611         return FLOW_ENULL;
00612     }
00613 
00614     /* save off a default base score */
00615     base_score = pstp->config.base_score;
00616     *score     = pstp->config.base_score;
00617 
00618     /* run the uniqueness check
00619      *
00620      * This should be ABOVE the finding code since the unquieness
00621      * check is the key to determining if this should accrue more
00622      * points. If it's not unique, we can bail out instantly.
00623      *
00624      */
00625 
00626     if(ut_check(&pstp->unique_tracker, &flowp->key, &unique) != FLOW_SUCCESS)
00627     {
00628 #ifndef WIN32
00629         flow_printf("ut check failed in %s\n", __func__);
00630 #else
00631         flow_printf("ut check failed in %s(%d)\n", __FILE__, __LINE__);
00632 #endif
00633         return 0;
00634     }
00635 
00636     
00637     if(unique == UT_OLD)
00638     {
00639         /* bail out if we do not have a reason to further evaluate the
00640          * score. The score can only be changed if this flow is truely
00641          * a unique (dport+proto+address)
00642          */
00643         *score = 0;
00644         return FLOW_SUCCESS;
00645     }
00646     else /* UT_NEW */
00647     {
00648         if(flowps_server_watch(pstp,flowp->key.resp_address) == FLOW_SUCCESS)
00649         {
00650             /* perform the hitcount management */            
00651             if(cur < (packet_first_time() + pstp->config.server_learning_time))
00652             {
00653                 if(server_stats_add_ipv4(&pstp->server_stats,
00654                                          flowp->key.protocol,
00655                                          flowp->key.resp_address,
00656                                          flowp->key.resp_port,
00657                                          &hitcount) != FLOW_SUCCESS)
00658                 {
00659 #ifdef DEBUG
00660                     flow_printf("Unable to add ipv4 to server stats!\n");
00661 #endif /* DEBUG */
00662                 }
00663                 
00664             }
00665             else
00666             {
00667                 hitcount = server_stats_hitcount_ipv4(&pstp->server_stats,
00668                                                       flowp->key.protocol,
00669                                                       flowp->key.resp_address,
00670                                                       flowp->key.resp_port);
00671 
00672                 if(pstp->config.server_scanner_limit &&
00673                    hitcount < pstp->config.server_scanner_limit)
00674                 {
00675                     *type = TRACKER_SCANNER;
00676                 }
00677             }
00678 
00679             if(pstp->config.server_ignore_limit > 0 &&
00680                hitcount > pstp->config.server_ignore_limit)
00681             {
00682                 /* this must be a semi-active service -- it's not worth
00683                  * anything */
00684                 
00685                 if(s_debug > 5)
00686                 {
00687                     flow_printf("Happy Server hitcount: %d proto: %d %s:%d\n",
00688                                 hitcount,
00689                                 flowp->key.protocol,
00690                                 inet_ntoa(*(struct in_addr *) &flowp->key.resp_address),
00691                                 flowp->key.resp_port);
00692                 }
00693                 
00694                 base_score = 0;
00695             }
00696             
00697         } /* this IP is not being watched or something like it */
00698         else
00699         {
00700             hitcount = 1;
00701         }
00702     }
00703 
00704     /*
00705      * possibly assign penalty points for "bad session initiators
00706      */
00707     if(pstp->config.tcp_penalties && flowp->key.protocol == 6)
00708     {        
00709         flowps_tcp_penalty(flags, base_score, score);
00710     }
00711     else
00712     {
00713         *score = base_score;
00714     }
00715 
00716     /* @todo switch tables */
00717     return FLOW_SUCCESS;
00718 }
00719 
00720 /** 
00721  * Expire a fixed scale PS_SCORE
00722  * 
00723  * @param pscp score entry to expire
00724  * @param current_time now
00725  * @param threshold threshold to slide againt
00726  * 
00727  * @return FLOW_SUCCESS
00728  */
00729 int flowps_fixed_winadj(PS_SCORE *pscp, time_t current_time,
00730                         SCORE_THRESHOLD *threshold)
00731 {
00732     int window_size = threshold->fixed_size;
00733 
00734     if(pscp->ends <= current_time)
00735     {
00736         pscp->start = current_time;
00737         pscp->score = 0;
00738         pscp->ends  = current_time + window_size;
00739     }
00740     
00741     return FLOW_SUCCESS;
00742 }
00743 
00744 /** 
00745  * Expire a sliding scale PS_SCORE
00746  *
00747  * considerably more complicated than the fixed time window
00748  * stuff. This really should be simplified.  
00749  * 
00750  * @param pscp score entry to expire
00751  * @param current_time current_time
00752  * @param threshold threshold to slide againt
00753  * 
00754  * @return FLOW_SUCCESS
00755  */
00756 int flowps_sliding_winadj(PS_SCORE *pscp, time_t current_time,
00757                           SCORE_THRESHOLD *threshold)
00758 {
00759     int diff_SE;     /* time from start to end */
00760     int diff_EN;     /* time from end to current_time */
00761     int window_size = threshold->sliding_size;
00762     int adjustment;        
00763     float scale     = threshold->window_scale;
00764     
00765     if(pscp->ends > current_time)
00766     {
00767         /* we're still in the right time frame -- should this
00768          *  increment the time frame? Seems to make sense but how
00769          *  often should the window "slide"?
00770          */
00771         return FLOW_SUCCESS;
00772     }
00773 
00774     /* we atleast kcurrent_time to expire the score */
00775     pscp->score = 0;
00776 
00777     if(pscp->ends == 0)
00778     {
00779         /* new time window, let's just initialize it */
00780         pscp->start = current_time;
00781         pscp->ends  = current_time + window_size;        
00782     }
00783     else
00784     {
00785         diff_SE = pscp->ends - pscp->start;
00786 
00787         /* since we never allow end > current_time, this will always be >=0  */    
00788         diff_EN = current_time - pscp->ends;
00789 
00790         if(diff_EN > (diff_SE * 2))
00791         {
00792             /* I've guessed at this one.  If the difference between end ->
00793              * current_time is much bigger than the previous time window, this is
00794              * good enough to start the sliding time frame over
00795              *
00796              * This could present a weakness in that 1 unique flow every N
00797              * scale could still slip past us.  It will always be possible
00798              * to slow the scan down though.  This should really decrease
00799              * the amount of benign active talkers.
00800              */
00801             pscp->start = current_time;
00802             pscp->ends  = current_time + window_size;        
00803         }
00804         else
00805         {
00806             pscp->start = current_time;
00807             adjustment = diff_SE + (diff_SE * scale);
00808             
00809             if((adjustment + pscp->ends) > pscp->ends)
00810             {
00811                 pscp->ends += adjustment;
00812             }
00813             else
00814             {
00815                 /* watching for integer wrap around incase an attacker
00816                  * causes our scales to wrapidly increase somehow
00817                  *
00818                  * We don't watch to make sure that the user doesn't
00819                  * screw us.
00820                  */
00821                 pscp->ends += window_size;
00822                 
00823             }
00824         }
00825     }
00826     
00827     return FLOW_SUCCESS;
00828 }
00829 
00830 /** 
00831  * Maintain the ring buffer of most recent connections
00832  * 
00833  * @param sep score entry pointer
00834  * @param flowp flow pointer
00835  * @param cflags connection flags ( often just the th_flags )
00836  * 
00837  * @return FLOW_SUCCESS on sucess
00838  */
00839 int flowps_set_last_address(SCORE_ENTRY *sep, FLOW *flowp, u_int8_t cflags)
00840 {
00841     CONN_ENTRY *conn_entry;
00842     
00843     if(sep && flowp)
00844     {
00845         if(sep->last_idx >= FLOWPS_HOSTS_SIZE)
00846         {
00847             sep->last_idx = 0;            
00848         }
00849 
00850         /* find the entry and increment the ring */
00851         conn_entry = &sep->last_hosts[sep->last_idx++];
00852 
00853         /* fill out the entry */
00854         conn_entry->port     = flowp->key.resp_port;
00855         conn_entry->ip       = flowp->key.resp_address;
00856         conn_entry->protocol = flowp->key.protocol;
00857         conn_entry->cflags   = cflags;
00858         /* increment how many connections this tracker has seen */
00859         sep->connections_seen++;
00860     }
00861     
00862     return FLOW_SUCCESS;
00863 }
00864 
00865 /** 
00866  * see if flowps is turned on
00867  * 
00868  * 
00869  * @return 1 if portscan is on
00870  */
00871 int flowps_enabled(void)
00872 {
00873     return s_enabled;
00874 }
00875 
00876 
00877 /** 
00878  * Check to see if this IPv4 Address should be ignored by the portscan
00879  * tracker.
00880  *
00881  * This checks both the src and dst lists.
00882  * 
00883  * @param pstp portscan tracker
00884  * @param sip pointer to the sip in NETWORK byte order
00885  * @param dip pointer to the dip in NETWORK byte order
00886  * 
00887  * @return FLOW_SUCCESS if this ip should be ignored, else it should be used
00888  */
00889 int flowps_is_ignored_ipv4(PS_TRACKER *pstp, u_int32_t *sip, u_int32_t *dip)
00890 {
00891     u_int32_t host_sip, host_dip; /**< host ordered addresses */
00892 
00893     if(pstp && sip && dip)
00894     {
00895         if(pstp->config.src_ignore_ipv4)
00896         {
00897             host_sip = ntohl(*sip);
00898 
00899             if(ipset_contains(pstp->config.src_ignore_ipv4,
00900                               &host_sip, IPV4_FAMILY))
00901             {
00902                 return FLOW_SUCCESS;
00903             }
00904         }
00905 
00906         if(pstp->config.dst_ignore_ipv4)
00907         {
00908             host_dip = ntohl(*dip);
00909 
00910             if(ipset_contains(pstp->config.dst_ignore_ipv4,
00911                               &host_dip, IPV4_FAMILY))
00912             {
00913                 return FLOW_SUCCESS;
00914             }
00915         }
00916 
00917         return FLOW_DISABLED;
00918     }
00919 
00920     return FLOW_ENULL;
00921 }

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