diff options
Diffstat (limited to 'LogActio/ThresholdWatch.py')
-rw-r--r-- | LogActio/ThresholdWatch.py | 173 |
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) + |