summaryrefslogtreecommitdiffstats
path: root/LogActio/ThresholdWatch.py
diff options
context:
space:
mode:
Diffstat (limited to 'LogActio/ThresholdWatch.py')
-rw-r--r--LogActio/ThresholdWatch.py173
1 files changed, 173 insertions, 0 deletions
diff --git a/LogActio/ThresholdWatch.py b/LogActio/ThresholdWatch.py
new file mode 100644
index 0000000..033109c
--- /dev/null
+++ b/LogActio/ThresholdWatch.py
@@ -0,0 +1,173 @@
+#
+# logactio - simple framework for doing configured action on certain
+# log file events
+#
+# Copyright 2013 David Sommerseth <dazo@users.sourceforge.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# For the avoidance of doubt the "preferred form" of this code is one which
+# is in an open unpatent encumbered format. Where cryptographic key signing
+# forms part of the process of creating an executable the information
+# including keys needed to generate an equivalently functional executable
+# are deemed to be part of the source code.
+#
+
+import hashlib, time
+
+
+class ThresholdType_Rule(object):
+ def __init__(self, params):
+ if not params.has_key("threshold"):
+ raise ValueError("Missing required 'threshold' parameter")
+
+ self.__threshold = int(params["threshold"])
+ self.__timeframe = params["timeframe"] and int(params["timeframe"]) or None
+ self.__ratelimit = params["ratelimit"] and int(params["ratelimit"]) or None
+ self.__lastseen = 0
+ self.__lastsent = 0
+ self.__currentcount = 0
+
+ def CheckThreshold(self, alert, notused_regexmatch):
+ now = int(time.time())
+ self.__currentcount += 1
+ ret = (self.__threshold == 0
+ or ((self.__currentcount % self.__threshold == 0)
+ and (self.__timeframe is None
+ or now <= (self.__lastseen + self.__timeframe)))
+ and (self.__ratelimit is None or now > (self.__lastsent + self.__ratelimit)))
+
+ if (self.__timeframe and (self.__lastseen > 0)
+ and (now >= (self.__lastseen + self.__timeframe))):
+ # If the time-frame have timed out, reset it
+ self.__lastseen = 0
+ else:
+ self.__lastseen = now
+
+ return ret
+
+
+ def ClearTimeTrackers(self, notused_regexmatch):
+ self.__lastseen = 0
+ self.__lastsent = 0
+
+
+ def GetThreshold(self):
+ return self.__threshold
+
+
+ def GetCurrentCount(self, rgmatch):
+ return self.__currentcount
+
+
+
+class ThresholdType_Exact(object):
+ def __init__(self, params):
+ self.__matchedgroups = {}
+
+ self.__threshold = int(params["threshold"])
+ self.__timeframe = params["timeframe"] and int(params["timeframe"]) or None
+ self.__ratelimit = params["ratelimit"] and int(params["ratelimit"]) or None
+
+
+ def __gen_hash(self, regexmatch):
+ return hashlib.sha384("|".join(regexmatch)).hexdigest()
+
+
+ def CheckThreshold(self, alert, regexmatch):
+ now = int(time.time())
+ ret = False
+
+ # If threshold is 0 or 1, then we process all records
+ if self.__threshold < 2:
+ return True
+
+ # Check if we have a regexmatch on this from earlier checks
+ rghash = self.__gen_hash(regexmatch)
+ if self.__matchedgroups.has_key(rghash):
+ lastevent = self.__matchedgroups[rghash]
+ lastevent["count"] += 1
+
+ ret = ((lastevent["count"] % self.__threshold == 0)
+ and (self.__timeframe is None
+ or now <= (lastevent["lastseen"] + self.__timeframe))
+ and (self.__ratelimit is None or now > (lastevent["lastsent"] + self.__ratelimit)))
+
+ if (self.__timeframe and (lastevent["lastseen"] > 0)
+ and (now >= (lastevent["lasteen"] + self.__timeframe))):
+ # If the time-frame have timed out, reset it
+ self.__lastseen = 0
+ else:
+ self.__lastseen = now
+ else:
+ # Not seen before, register it as a new one
+ self.__matchedgroups[rghash] = {
+ "count": 1,
+ "lastseen": now,
+ "lastsent": 0
+ }
+ ret = (1 % self.__threshold == 0)
+
+ return ret
+
+
+ def ClearTimeTrackers(self, regexmatch):
+ rghash = self.__gen_hash(regexmatch)
+ if self.__matchedgroups.has_key(rghash):
+ self.__matchedgroups[rghash]["lasteen"] = 0
+ self.__matchedgroups[rghash]["lastsent"] = 0
+
+
+ def GetThreshold(self):
+ return self.__threshold
+
+
+ def GetCurrentCount(self, regexmatch):
+ rghash = self.__gen_hash(regexmatch)
+ if self.__matchedgroups.has_key(rghash):
+ return self.__matchedgroups[rghash]["count"]
+ else:
+ return 0
+
+
+
+class ThresholdWatch(object):
+ WATCHTYPE_RULE = 1
+ WATCHTYPE_EXACT = 2
+
+ def __init__(self, watchtype, params):
+ self.__watchtype = watchtype
+ if watchtype == self.WATCHTYPE_RULE:
+ self.__thresholdtype = ThresholdType_Rule(params)
+ elif watchtype == self.WATCHTYPE_EXACT:
+ self.__thresholdtype = ThresholdType_Exact(params)
+ else:
+ raise ValueError("Invalid watchtype parameter")
+
+
+ def CheckThreshold(self, alert, regexmatch):
+ return self.__thresholdtype.CheckThreshold(alert, regexmatch)
+
+
+ def ClearTimeTrackers(self, regexmatch):
+ self.__thresholdtype.ClearTimeTrackers(regexmatch)
+
+
+ def GetThreshold(self):
+ return self.__thresholdtype.GetThreshold()
+
+
+ def GetCurrentCount(self, regexmatch):
+ return self.__thresholdtype.GetCurrentCount(regexmatch)
+