diff src/syslogconfig.cpp @ 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 206448c00b55
children f133196b8591
line wrap: on
line diff
--- 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);