"Fossies" - the Fresh Open Source Software Archive

Member "fail2ban-0.11.1/fail2ban/server/failmanager.py" (11 Jan 2020, 5352 Bytes) of package /linux/misc/fail2ban-0.11.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "failmanager.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.10.5_vs_0.11.1.

    1 # emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
    2 # vi: set ft=python sts=4 ts=4 sw=4 noet :
    3 
    4 # This file is part of Fail2Ban.
    5 #
    6 # Fail2Ban is free software; you can redistribute it and/or modify
    7 # it under the terms of the GNU General Public License as published by
    8 # the Free Software Foundation; either version 2 of the License, or
    9 # (at your option) any later version.
   10 #
   11 # Fail2Ban is distributed in the hope that it will be useful,
   12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 # GNU General Public License for more details.
   15 #
   16 # You should have received a copy of the GNU General Public License
   17 # along with Fail2Ban; if not, write to the Free Software
   18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   19 
   20 # Author: Cyril Jaquier
   21 # 
   22 
   23 __author__ = "Cyril Jaquier"
   24 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
   25 __license__ = "GPL"
   26 
   27 from threading import Lock
   28 import logging
   29 
   30 from .ticket import FailTicket, BanTicket
   31 from ..helpers import getLogger, BgService
   32 
   33 # Gets the instance of the logger.
   34 logSys = getLogger(__name__)
   35 logLevel = logging.DEBUG
   36 
   37 
   38 class FailManager:
   39     
   40     def __init__(self):
   41         self.__lock = Lock()
   42         self.__failList = dict()
   43         self.__maxRetry = 3
   44         self.__maxTime = 600
   45         self.__failTotal = 0
   46         self.maxMatches = 50
   47         self.__bgSvc = BgService()
   48     
   49     def setFailTotal(self, value):
   50         with self.__lock:
   51             self.__failTotal = value
   52         
   53     def getFailTotal(self):
   54         with self.__lock:
   55             return self.__failTotal
   56     
   57     def getFailCount(self):
   58         # may be slow on large list of failures, should be used for test purposes only...
   59         with self.__lock:
   60             return len(self.__failList), sum([f.getRetry() for f in self.__failList.values()])
   61 
   62     def getFailTotal(self):
   63         with self.__lock:
   64             return self.__failTotal
   65 
   66     def setMaxRetry(self, value):
   67         self.__maxRetry = value
   68     
   69     def getMaxRetry(self):
   70         return self.__maxRetry
   71     
   72     def setMaxTime(self, value):
   73         self.__maxTime = value
   74     
   75     def getMaxTime(self):
   76         return self.__maxTime
   77 
   78     def addFailure(self, ticket, count=1, observed=False):
   79         attempts = 1
   80         with self.__lock:
   81             fid = ticket.getID()
   82             try:
   83                 fData = self.__failList[fid]
   84                 # if the same object - the same matches but +1 attempt:
   85                 if fData is ticket:
   86                     matches = None
   87                     attempt = 1
   88                 else:
   89                     # will be incremented / extended (be sure we have at least +1 attempt):
   90                     matches = ticket.getMatches() if self.maxMatches else None
   91                     attempt = ticket.getAttempt()
   92                     if attempt <= 0:
   93                         attempt += 1
   94                 unixTime = ticket.getTime()
   95                 fData.setLastTime(unixTime)
   96                 if fData.getLastReset() < unixTime - self.__maxTime:
   97                     fData.setLastReset(unixTime)
   98                     fData.setRetry(0)
   99                 fData.inc(matches, attempt, count)
  100                 # truncate to maxMatches:
  101                 if self.maxMatches:
  102                     matches = fData.getMatches()
  103                     if len(matches) > self.maxMatches:
  104                         fData.setMatches(matches[-self.maxMatches:])
  105                 else:
  106                     fData.setMatches(None)
  107             except KeyError:
  108                 # not found - already banned - prevent to add failure if comes from observer:
  109                 if observed or isinstance(ticket, BanTicket):
  110                     return ticket.getRetry()
  111                 # if already FailTicket - add it direct, otherwise create (using copy all ticket data):
  112                 if isinstance(ticket, FailTicket):
  113                     fData = ticket;
  114                 else:
  115                     fData = FailTicket.wrap(ticket)
  116                 if count > ticket.getAttempt():
  117                     fData.setRetry(count)
  118                 self.__failList[fid] = fData
  119 
  120             attempts = fData.getRetry()
  121             self.__failTotal += 1
  122 
  123             if logSys.getEffectiveLevel() <= logLevel:
  124                 # yoh: Since composing this list might be somewhat time consuming
  125                 # in case of having many active failures, it should be ran only
  126                 # if debug level is "low" enough
  127                 failures_summary = ', '.join(['%s:%d' % (k, v.getRetry())
  128                                               for k,v in  self.__failList.iteritems()])
  129                 logSys.log(logLevel, "Total # of detected failures: %d. Current failures from %d IPs (IP:count): %s"
  130                              % (self.__failTotal, len(self.__failList), failures_summary))
  131 
  132         self.__bgSvc.service()
  133         return attempts
  134     
  135     def size(self):
  136         with self.__lock:
  137             return len(self.__failList)
  138     
  139     def cleanup(self, time):
  140         with self.__lock:
  141             todelete = [fid for fid,item in self.__failList.iteritems() \
  142                 if item.getLastTime() + self.__maxTime <= time]
  143             if len(todelete) == len(self.__failList):
  144                 # remove all:
  145                 self.__failList = dict()
  146             elif not len(todelete):
  147                 # nothing:
  148                 return
  149             if len(todelete) / 2.0 <= len(self.__failList) / 3.0:
  150                 # few as 2/3 should be removed - remove particular items:
  151                 for fid in todelete:
  152                     del self.__failList[fid]
  153             else:
  154                 # create new dictionary without items to be deleted:
  155                 self.__failList = dict((fid,item) for fid,item in self.__failList.iteritems() \
  156                     if item.getLastTime() + self.__maxTime > time)
  157         self.__bgSvc.service()
  158     
  159     def delFailure(self, fid):
  160         with self.__lock:
  161             try:
  162                 del self.__failList[fid]
  163             except KeyError:
  164                 pass
  165     
  166     def toBan(self, fid=None):
  167         with self.__lock:
  168             for fid in ([fid] if fid is not None and fid in self.__failList else self.__failList):
  169                 data = self.__failList[fid]
  170                 if data.getRetry() >= self.__maxRetry:
  171                     del self.__failList[fid]
  172                     return data
  173         self.__bgSvc.service()
  174         raise FailManagerEmpty
  175 
  176 
  177 class FailManagerEmpty(Exception):
  178     pass