changeset 58:b45dddebe8fc

Add exponential increase in penalty for repeat offenders
author Carl Byington <carl@five-ten-sg.com>
date Tue, 10 Jun 2014 08:48:53 -0700
parents c95acc20f7ed
children f133196b8591
files ChangeLog NEWS configure.in src/syslogconfig.cpp src/syslogconfig.h syslog2iptables.conf syslog2iptables.spec.in xml/syslog2iptables.in
diffstat 8 files changed, 116 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Aug 17 10:16:17 2011 -0700
+++ b/ChangeLog	Tue Jun 10 08:48:53 2014 -0700
@@ -1,3 +1,6 @@
+1.14 2014-06-10
+     Add exponential increase in penalty for repeat offenders.
+
 1.13 2011-08-17
      Switch to auto requires for rpm builds.
 
--- a/NEWS	Wed Aug 17 10:16:17 2011 -0700
+++ b/NEWS	Tue Jun 10 08:48:53 2014 -0700
@@ -1,3 +1,4 @@
+1.14 2014-06-10 Add exponential increase in penalty for repeat offenders.
 1.13 2009-01-25 Document multiple contexts.
 1.12 2009-01-24 Allow multiple contexts with independent add/remove commands.
 1.11 2008-05-29 Fixes to compile on Fedora 9 and for const correctness.
--- a/configure.in	Wed Aug 17 10:16:17 2011 -0700
+++ b/configure.in	Tue Jun 10 08:48:53 2014 -0700
@@ -1,6 +1,6 @@
 
 AC_PREREQ(2.59)
-AC_INIT(syslog2iptables,1.13,carl@five-ten-sg.com)
+AC_INIT(syslog2iptables,1.14,carl@five-ten-sg.com)
 AC_CONFIG_SRCDIR([config.h.in])
 AC_CONFIG_HEADER([config.h])
 
--- a/src/syslogconfig.cpp	Wed Aug 17 10:16:17 2011 -0700
+++ b/src/syslogconfig.cpp	Tue Jun 10 08:48:53 2014 -0700
@@ -32,6 +32,7 @@
 string_set      all_strings;// owns all the strings, only modified by the config loader thread
 recorder_map    recorders;  // all the recorders are named
 const int maxlen = 1000;    // used for snprintf buffers
+const int scale_max = 500000;
 
 
 ////////////////////////////////////////////////
@@ -39,6 +40,7 @@
 
 IPR::IPR() {
     reference_count = 0;
+    daily_timer     = 86400;
 }
 
 IPR* IPR::find(const char* name) {
@@ -62,26 +64,28 @@
 
 void IPR::add(int ip, int amount, CONTEXT &con, const char *file_name, int pattern_index, const char *message) {
     if (con.looking(ip)) {
+        ip_buckets::iterator j = repeat_offenders.find(ip);
+        int scale = (j == repeat_offenders.end()) ? 1 : (*j).second.count;
+        amount *= scale;
+
         ip_buckets::iterator i = violations.find(ip);
         if (i == violations.end()) {
             bucket b;
             b.count = amount;
-            b.latch = (con.get_threshold() <= b.count);
+            b.blocked = (con.get_threshold() <= b.count);
             violations[ip] = b;
-            if (b.latch) {
-                update(ip, true, file_name, pattern_index, message);
+            if (b.blocked) {
+                update(ip, true, scale, file_name, pattern_index, message);
                 changed(con, ip, true);
             }
         }
         else {
             bucket &b = (*i).second;
             if (b.count < (INT_MAX-amount)) {
-                int t = con.get_threshold();
-                int c = b.count;
                 b.count += amount;
-                if ((!b.latch) && (c < t) && (t <= b.count)) {
-                    b.latch = true;
-                    update(ip, true, file_name, pattern_index, message);
+                if ((!b.blocked) && (con.get_threshold() <= b.count)) {
+                    b.blocked = true;
+                    update(ip, true, scale, file_name, pattern_index, message);
                     changed(con, ip, true);
                 }
             }
@@ -95,8 +99,8 @@
         int    ip = (*i).first;
         bucket &b = (*i).second;
         if (b.count <= amount) {
-            if (b.latch) {
-                update(ip, false, NULL, 0, NULL);
+            if (b.blocked) {
+                update(ip, false, 0, NULL, 0, NULL);
                 changed(con, ip, false);
             }
             violations.erase(i++);
@@ -106,6 +110,26 @@
             i++;
         }
     }
+    daily_timer -= amount;
+    if (daily_timer < 0) {
+        daily_timer = 86400;
+        for (ip_buckets::iterator j=repeat_offenders.begin(); j!=repeat_offenders.end(); ) {
+            int    ip = (*j).first;
+            bucket &b = (*j).second;
+            b.count = b.count * 2 / 3;
+            if (b.count <= 2) {
+                repeat_offenders.erase(j++);
+                char buf[maxlen];
+                in_addr ad;
+                ad.s_addr = htonl(ip);
+                snprintf(buf, maxlen, "removing %s from repeat offenders", inet_ntoa(ad));
+                my_syslog(buf);
+            }
+            else {
+                j++;
+            }
+        }
+    }
 }
 
 
@@ -116,8 +140,8 @@
     for (ip_buckets::iterator i=violations.begin(); i!=violations.end(); i++) {
         int    ip = (*i).first;
         bucket &b = (*i).second;
-        if (b.latch) {
-            update(ip, false, NULL, 0, NULL);
+        if (b.blocked) {
+            update(ip, false, 0, NULL, 0, NULL);
             changed(con, ip, false);
         }
     }
@@ -125,14 +149,25 @@
 }
 
 
-void IPR::update(int ip, bool added, const char *file_name, int pattern_index, const char *message) {
+void IPR::update(int ip, bool added, int scale, const char *file_name, int pattern_index, const char *message) {
     if (debug_syslog > 2) {
         char buf[maxlen];
         in_addr ad;
         ad.s_addr = htonl(ip);
         if (added) {
-            if (message) snprintf(buf, maxlen, "dropping traffic from/to %s based on %s in %s", inet_ntoa(ad), message, file_name);
+            if (message) snprintf(buf, maxlen, "dropping traffic from/to %s based on %s in %s, scale %d", inet_ntoa(ad), message, file_name, scale);
             else         snprintf(buf, maxlen, "dropping traffic from/to %s based on pattern match %d in %s", inet_ntoa(ad), pattern_index, file_name);
+            ip_buckets::iterator j = repeat_offenders.find(ip);
+            if (j == repeat_offenders.end()) {
+                bucket b;
+                b.count = 2;
+                b.blocked = true;   // unused
+                repeat_offenders[ip] = b;
+            }
+            else {
+                bucket &b = (*j).second;
+                if (b.count < scale_max) b.count = b.count * 3 / 2;
+            }
         }
         else       snprintf(buf, maxlen, "allowing traffic from/to %s", inet_ntoa(ad));
         my_syslog(buf);
--- a/src/syslogconfig.h	Wed Aug 17 10:16:17 2011 -0700
+++ b/src/syslogconfig.h	Tue Jun 10 08:48:53 2014 -0700
@@ -40,21 +40,23 @@
 
 struct bucket {
     int  count;
-    bool latch; // true iff ever count>threshold
+    bool blocked; // true iff ever count>threshold
 };
 
 typedef map<int, bucket, ltint>   ip_buckets;
 
 class IPR {
     int         reference_count;    // number of contexts using this recorder
+    int         daily_timer;        // track daily cycle to reduce repeat offenders penalties
     ip_buckets  violations;
+    ip_buckets  repeat_offenders;
 public:
     IPR();
     int  reference(int delta)   {reference_count += delta; return reference_count;};
     void add(int ip, int amount, CONTEXT &con, const char *file_name, int pattern_index, const char *message);
     void leak(int amount, CONTEXT &con);
     void free_all(CONTEXT &con);
-    void update(int ip, bool added, const char *file_name, int pattern_index, const char *message);
+    void update(int ip, bool added, int scale, const char *file_name, int pattern_index, const char *message);
     void changed(CONTEXT &con, int ip, bool added);
     static IPR* find(const char* name);
     static void release(const char* name);
--- a/syslog2iptables.conf	Wed Aug 17 10:16:17 2011 -0700
+++ b/syslog2iptables.conf	Tue Jun 10 08:48:53 2014 -0700
@@ -1,23 +1,3 @@
-context dns {
-    threshold 1100;
-
-    add_command    "/sbin/iptables -I INPUT --protocol udp --destination-port 53 --src %s --jump DROP";
-    remove_command "/sbin/iptables -D INPUT --protocol udp --destination-port 53 --src %s --jump DROP";
-
-    ignore {
-        127.0.0.0/8;        // localhost
-    };
-
-    file "/var/log/messages" {
-        pattern "named.*client (.*)#.*query.*cache.*'\./NS/IN'.*denied" {
-            index 1;    // zero based
-            bucket 400;
-            message "DNS attack";
-        };
-    };
-};
-
-
 context general {
     threshold 550;
 
@@ -39,11 +19,26 @@
             bucket 400;
             message "ssh failed password";
         };
+        pattern "sshd.*authentication failure; .* rhost=(.*) " {
+            index 1;    // zero based
+            bucket 400;
+            message "ssh failed password";
+        };
+        pattern "sshd.*Did not receive identification string from (.*)" {
+            index 1;    // zero based
+            bucket 400;
+            message "ssh failed password";
+        };
         pattern "proftpd.*no such user found from (.*) \[" {
             index 1;    // zero based
             bucket 400;
             message "ftp failed password";
         };
+        pattern "proftpd.* authentication failure; .* rhost=(.*) " {
+            index 1;    // zero based
+            bucket 400;
+            message "ftp failed password";
+        };
         pattern "vsftpd.* authentication failure; .* rhost=(.*) " {
             index 1;    // zero based
             bucket 400;
@@ -98,6 +93,11 @@
             bucket 400;
             message "apache awstats.pl reference";
         };
+        pattern "(.*) - - .*/xmlrpc" {
+            index 1;    // zero based
+            bucket 400;
+            message "apache xmlrpc reference";
+        };
         pattern "(.*) - - .*/adxmlrpc" {
             index 1;    // zero based
             bucket 400;
@@ -108,11 +108,36 @@
             bucket 400;
             message "apache general.js reference";
         };
+        pattern "(.*) - - .*/Admin/" {
+            index 1;    // zero based
+            bucket 400;
+            message "apache phpMyAdmin reference";
+        };
+        pattern "(.*) - - .*/MyAdmin/" {
+            index 1;    // zero based
+            bucket 400;
+            message "apache phpMyAdmin reference";
+        };
         pattern "(.*) - - .*/phpMyAdmin/" {
             index 1;    // zero based
             bucket 400;
             message "apache phpMyAdmin reference";
         };
+        pattern "(.*) - - .*/user/soapCaller" {
+            index 1;    // zero based
+            bucket 400;
+            message "apache soapCaller reference";
+        };
+        pattern "(.*) - - .*POST /contact.php" {
+            index 1;    // zero based
+            bucket 400;
+            message "apache contact.php post";
+        };
+        pattern "(.*) - - .*/crossdomain.xml" {
+            index 1;    // zero based
+            bucket 400;
+            message "apache crossdomain.xml reference";
+        };
         pattern "(.*) - - .*/cart/" {
             index 1;    // zero based
             bucket 400;
@@ -143,7 +168,7 @@
         };
         pattern "rejecting commands from .* \[(.*)\] due to pre-greeting traffic" {
             index 1;    // zero based
-            bucket 200;
+            bucket 1800;
             message "sendmail pre-greeting";
         };
         pattern "dovecot.*Aborted login.*rip=(.*)," {
--- a/syslog2iptables.spec.in	Wed Aug 17 10:16:17 2011 -0700
+++ b/syslog2iptables.spec.in	Tue Jun 10 08:48:53 2014 -0700
@@ -3,7 +3,7 @@
 Summary:            Syslog to iptables dynamic firewall
 Name:               @PACKAGE@
 Version:            @VERSION@
-Release:            2%{?dist}
+Release:            1%{?dist}
 License:            GPLv3+
 Group:              System Environment/Daemons
 Source:             http://www.five-ten-sg.com/%{name}/packages/%{name}-%{version}.tar.gz
@@ -67,6 +67,9 @@
 
 
 %changelog
+* Tue Jun 10 2014 Carl Byington <carl@five-ten-sg.com> - 1.14-1
+- Add exponential increase in penalty for repeat offenders.
+
 * Wed Aug 17 2011 Carl Byington <carl@five-ten-sg.com> - 1.13-2
 - switch to auto requires
 
--- a/xml/syslog2iptables.in	Wed Aug 17 10:16:17 2011 -0700
+++ b/xml/syslog2iptables.in	Tue Jun 10 08:48:53 2014 -0700
@@ -20,6 +20,13 @@
     <refentry id="@PACKAGE@.1">
         <refentryinfo>
             <date>2009-01-25</date>
+            <author>
+                <firstname>Carl</firstname>
+                <surname>Byington</surname>
+                <affiliation>
+                     <orgname>510 Software Group</orgname>
+                </affiliation>
+            </author>
         </refentryinfo>
 
         <refmeta>