Added MAX_SCAN_IP_PAIRS
authorMichael Rash <mbr@cipherdyne.org>
Sat, 10 Dec 2011 19:49:21 +0000 (14:49 -0500)
committerMichael Rash <mbr@cipherdyne.org>
Sat, 10 Dec 2011 19:49:21 +0000 (14:49 -0500)
Thic commit allows psad memory usage to be constrained by restricting the
number of unique IP pairs that psad tracks via a new config variable
MAX_SCAN_IP_PAIRS.  This is useful for when psad is deployed on systems with
little memory, and is best utilized in conjunction with disabling
ENABLE_PERSISTENCE so that old scans will also be deleted (and thereby making
room for tracking new scans under the MAX_SCAN_IP_PAIRS threshold).

psad
psad.conf

diff --git a/psad b/psad
index f95e66b..ebbe639 100755 (executable)
--- a/psad
+++ b/psad
@@ -268,6 +268,9 @@ my $year = '';
 ### useful for TOP_SCANS_CTR_THRESHOLD
 my $check_interval_ctr = 0;
 
+### track the number of scan IP pairs for MAX_SCAN_IP_PAIRS thresholding
+my $scan_ip_pairs = 0;
+
 ### %auto_dl holds all ip addresses that should automatically
 ### be assigned a danger level (or ignored).
 my %auto_dl = ();
@@ -1017,6 +1020,7 @@ sub check_scan() {
     my %auto_block_regex_match = ();
 
     my $pkt_ctr = 0;
+    my $log_scan_ip_pair_max = 0;
 
     my $print_scale_factor = &get_scale_factor($#$fw_packets_ar);
 
@@ -1061,14 +1065,33 @@ sub check_scan() {
             $top_udplite_ports{$pkt{'dp'}}++;
         }
 
-        ### track packet counts for this source
-        $top_packet_counts{$pkt{'src'}}++;
-
         ### If we made it here then we correctly matched packets
         ### that the firewall logged.
         print STDERR "[+] valid packet: $pkt{'src'} ($pkt{'sp'}) -> ",
             "$pkt{'dst'} ($pkt{'dp'}) $pkt{'proto'}\n" if $debug;
 
+        ### see if we have hit the MAX_SCAN_IP_PAIRS threshold
+        if ($config{'MAX_SCAN_IP_PAIRS'} > 0) {
+            if ($scan_ip_pairs >= $config{'MAX_SCAN_IP_PAIRS'}) {
+                unless (defined $scan{$pkt{'src'}}
+                        and defined $scan{$pkt{'src'}}{$pkt{'dst'}}) {
+                    print STDERR "[-] excluding $pkt{'src'} -> $pkt{'dst'}, ",
+                            "scan IP pairs too high: $scan_ip_pairs\n"
+                        if $debug;
+                    $log_scan_ip_pair_max = 1;
+                    next PKT;
+                }
+            }
+            if (not defined $scan{$pkt{'src'}}) {
+                $scan_ip_pairs++;
+            } elsif (not defined $scan{$pkt{'src'}}{$pkt{'dst'}}) {
+                $scan_ip_pairs++;
+            }
+        }
+
+        ### track packet counts for this source
+        $top_packet_counts{$pkt{'src'}}++;
+
         if ($config{'HOME_NET'} ne 'any') {
             if ($pkt{'chain'} eq 'INPUT') {
                 $local_src{$pkt{'dst'}} = '';
@@ -1139,6 +1162,7 @@ sub check_scan() {
                 }
             }
         }
+
         ### note that we send this packet data off to DShield regardless
         ### of whether psad decides that it is associated with a scan so
         ### that DShield can make its own determination
@@ -1306,6 +1330,10 @@ sub check_scan() {
     &auto_psad_response(\%curr_scan, \%auto_block_regex_match)
         if $config{'ENABLE_AUTO_IDS'} eq 'Y' and not $analyze_mode;
 
+    if ($log_scan_ip_pair_max) {
+        &sys_log("scan IP pairs threshold reached");
+    }
+
     return;
 }
 
@@ -2852,7 +2880,12 @@ sub delete_old_scans() {
                     >= $config{'SCAN_TIMEOUT'}) {
                 print STDERR "    delete old scan $src -> $dst\n"
                     if $debug;
+
                 delete $scan{$src}{$dst};
+
+                if ($config{'MAX_SCAN_IP_PAIRS'} > 0) {
+                    $scan_ip_pairs-- if $scan_ip_pairs > 0;
+                }
             }
         }
     }
@@ -7066,6 +7099,7 @@ sub analysis_mode() {
     &check_scan(\@ipt_msgs);
 
     print "\n[+] Finished --Analyze cycle.\n";
+
     return 0;
 }
 
@@ -10325,7 +10359,7 @@ sub required_vars() {
         ENABLE_SYSLOG_FILE IPT_SYSLOG_FILE IPT_WRITE_FWDATA
         ETC_RSYSLOG_CONF IFCFGTYPE ENABLE_WHOIS_FORCE_ASCII
         ENABLE_WHOIS_FORCE_SRC_IP ENABLE_IPV6_DETECTION
-        PERSISTENCE_CTR_THRESHOLD
+        PERSISTENCE_CTR_THRESHOLD MAX_SCAN_IP_PAIRS
     );
     &defined_vars(\@required_vars);
     return;
index a95fd84..513f617 100644 (file)
--- a/psad.conf
+++ b/psad.conf
@@ -102,12 +102,21 @@ ENABLE_PERSISTENCE          Y;
 SCAN_TIMEOUT                3600;  ### seconds
 
 ### Specify how often to timeout old scan data relative to CHECK_INTERVAL
-### iterations.  This feature is only use if ENABLE_PERSISTENCE is disabled.
+### iterations.  This feature is only used if ENABLE_PERSISTENCE is disabled.
 ### Note that for psad processes that have tracked a lot of scans, it is
 ### advisable to leave this threshold at the default value of 5 or greater
 ### because the scan tracking hash may be quite large.
 PERSISTENCE_CTR_THRESHOLD   5;
 
+### Limit the number of src->dst IP pairs that psad will track.  The default
+### is zero (i.e. unlimited), but if psad is running on a system with limited
+### memory, this can be handy to restrict psad's memory usage.  It is best to
+### combine this option with disabling ENABLE_PERSISTENCE so that older scans
+### are deleted and therefore newer scans will on average continue to be
+### tracked.  A good non-zero value is, say, 50000, but this will vary
+### depending on available system memory.
+MAX_SCAN_IP_PAIRS           0;
+
 ### If "Y", means all signatures will be shown since
 ### the scan started instead of just the current ones.
 SHOW_ALL_SIGNATURES         N;