"Fossies" - the Fresh Open Source Software Archive

Member "fail2ban-0.11.1/fail2ban/server/ticket.py" (11 Jan 2020, 8159 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 "ticket.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 ..helpers import getLogger
   28 from .ipdns import IPAddr
   29 from .mytime import MyTime
   30 
   31 # Gets the instance of the logger.
   32 logSys = getLogger(__name__)
   33 
   34 
   35 class Ticket(object):
   36     __slots__ = ('_ip', '_flags', '_banCount', '_banTime', '_time', '_data', '_retry', '_lastReset')
   37 
   38     MAX_TIME = 0X7FFFFFFFFFFF ;# 4461763-th year
   39     
   40     RESTORED = 0x01
   41     BANNED   = 0x08
   42 
   43     def __init__(self, ip=None, time=None, matches=None, data={}, ticket=None):
   44         """Ticket constructor
   45 
   46         @param ip the IP address
   47         @param time the ban time
   48         @param matches (log) lines caused the ticket
   49         """
   50 
   51         self.setIP(ip)
   52         self._flags = 0;
   53         self._banCount = 0;
   54         self._banTime = None;
   55         self._time = time if time is not None else MyTime.time()
   56         self._data = {'matches': matches or [], 'failures': 0}
   57         if data is not None:
   58             for k,v in data.iteritems():
   59                 if v is not None:
   60                     self._data[k] = v
   61         if ticket:
   62             # ticket available - copy whole information from ticket:
   63             self.update(ticket)
   64             #self.__dict__.update(i for i in ticket.__dict__.iteritems() if i[0] in self.__dict__)
   65 
   66     def __str__(self):
   67         return "%s: ip=%s time=%s bantime=%s bancount=%s #attempts=%d matches=%r" % \
   68                  (self.__class__.__name__.split('.')[-1], self._ip, self._time,
   69                     self._banTime, self._banCount,
   70                     self._data['failures'], self._data.get('matches', []))
   71 
   72     def __repr__(self):
   73         return str(self)
   74 
   75     def __eq__(self, other):
   76         try:
   77             return self._ip == other._ip and \
   78                 round(self._time, 2) == round(other._time, 2) and \
   79                 self._data == other._data
   80         except AttributeError:
   81             return False
   82 
   83     def update(self, ticket):
   84         for n in ticket.__slots__:
   85             v = getattr(ticket, n, None)
   86             if v is not None:
   87                 setattr(self, n, v)
   88 
   89 
   90     def setIP(self, value):
   91         # guarantee using IPAddr instead of unicode, str for the IP
   92         if isinstance(value, basestring):
   93             value = IPAddr(value)
   94         self._ip = value
   95     
   96     def getID(self):
   97         return self._data.get('fid', self._ip)
   98     
   99     def getIP(self):
  100         return self._ip
  101     
  102     def setTime(self, value):
  103         self._time = value
  104     
  105     def getTime(self):
  106         return self._time
  107 
  108     def setBanTime(self, value):
  109         self._banTime = value
  110 
  111     def getBanTime(self, defaultBT=None):
  112         return (self._banTime if self._banTime is not None else defaultBT)
  113 
  114     def setBanCount(self, value, always=False):
  115         if always or value > self._banCount:
  116             self._banCount = value
  117 
  118     def incrBanCount(self, value=1):
  119         self._banCount += value
  120 
  121     def getBanCount(self):
  122         return self._banCount;
  123 
  124     def getEndOfBanTime(self, defaultBT=None):
  125         bantime = (self._banTime if self._banTime is not None else defaultBT)
  126         # permanent
  127         if bantime == -1:
  128             return Ticket.MAX_TIME
  129         # unban time (end of ban):
  130         return self._time + bantime
  131 
  132     def isTimedOut(self, time, defaultBT=None):
  133         bantime = (self._banTime if self._banTime is not None else defaultBT)
  134         # permanent
  135         if bantime == -1:
  136             return False
  137         # timed out
  138         return (time > self._time + bantime)
  139 
  140     def setAttempt(self, value):
  141         self._data['failures'] = value
  142     
  143     def getAttempt(self):
  144         return self._data['failures']
  145 
  146     def setMatches(self, matches):
  147         if matches:
  148             self._data['matches'] = matches
  149         else:
  150             try:
  151                 del self._data['matches']
  152             except KeyError:
  153                 pass
  154 
  155     def getMatches(self):
  156         return [(line if not isinstance(line, (list, tuple)) else "".join(line)) \
  157             for line in self._data.get('matches', ())]
  158 
  159     @property
  160     def restored(self):
  161         return self._flags & Ticket.RESTORED
  162     @restored.setter
  163     def restored(self, value):
  164         if value:
  165             self._flags |= Ticket.RESTORED
  166         else:
  167             self._flags &= ~(Ticket.RESTORED)
  168     
  169     @property
  170     def banned(self):
  171         return self._flags & Ticket.BANNED
  172     @banned.setter
  173     def banned(self, value):
  174         if value:
  175             self._flags |= Ticket.BANNED
  176         else:
  177             self._flags &= ~(Ticket.BANNED)
  178 
  179     def setData(self, *args, **argv):
  180         # if overwrite - set data and filter None values:
  181         if len(args) == 1:
  182             # todo: if support >= 2.7 only:
  183             # self._data = {k:v for k,v in args[0].iteritems() if v is not None}
  184             self._data = dict([(k,v) for k,v in args[0].iteritems() if v is not None])
  185         # add k,v list or dict (merge):
  186         elif len(args) == 2:
  187             self._data.update((args,))
  188         elif len(args) > 2:
  189             self._data.update((k,v) for k,v in zip(*[iter(args)]*2))
  190         if len(argv):
  191             self._data.update(argv)
  192         # filter (delete) None values:
  193         # todo: if support >= 2.7 only:
  194         # self._data = {k:v for k,v in self._data.iteritems() if v is not None}
  195         self._data = dict([(k,v) for k,v in self._data.iteritems() if v is not None])
  196     
  197     def getData(self, key=None, default=None):
  198         # return whole data dict:
  199         if key is None:
  200             return self._data
  201         # return default if not exists:
  202         if not self._data:
  203             return default
  204         if not isinstance(key,(str,unicode,type(None),int,float,bool,complex)):
  205             # return filtered by lambda/function:
  206             if callable(key):
  207                 # todo: if support >= 2.7 only:
  208                 # return {k:v for k,v in self._data.iteritems() if key(k)}
  209                 return dict([(k,v) for k,v in self._data.iteritems() if key(k)])
  210             # return filtered by keys:
  211             if hasattr(key, '__iter__'):
  212                 # todo: if support >= 2.7 only:
  213                 # return {k:v for k,v in self._data.iteritems() if k in key}
  214                 return dict([(k,v) for k,v in self._data.iteritems() if k in key])
  215         # return single value of data:
  216         return self._data.get(key, default)
  217 
  218     @property
  219     def banEpoch(self):
  220         return getattr(self, '_banEpoch', 0)
  221     @banEpoch.setter
  222     def banEpoch(self, value):
  223         self._banEpoch = value
  224 
  225 
  226 class FailTicket(Ticket):
  227 
  228     def __init__(self, ip=None, time=None, matches=None, data={}, ticket=None):
  229         # this class variables:
  230         self._retry = 0
  231         self._lastReset = None
  232         # create/copy using default ticket constructor:
  233         Ticket.__init__(self, ip, time, matches, data, ticket)
  234         # init:
  235         if ticket is None:
  236             self._lastReset = time if time is not None else self.getTime()
  237         if not self._retry:
  238             self._retry = self._data['failures'];
  239 
  240     def setRetry(self, value):
  241         """ Set artificial retry count, normally equal failures / attempt,
  242         used in incremental features (BanTimeIncr) to increase retry count for bad IPs
  243         """
  244         self._retry = value
  245         if not self._data['failures']:
  246             self._data['failures'] = 1
  247         if not value:
  248             self._data['failures'] = 0
  249             self._data['matches'] = []
  250 
  251     def getRetry(self):
  252         """ Returns failures / attempt count or
  253         artificial retry count increased for bad IPs
  254         """
  255         return max(self._retry, self._data['failures'])
  256 
  257     def inc(self, matches=None, attempt=1, count=1):
  258         self._retry += count
  259         self._data['failures'] += attempt
  260         if matches:
  261             # we should duplicate "matches", because possibly referenced to multiple tickets:
  262             if self._data['matches']:
  263                 self._data['matches'] = self._data['matches'] + matches
  264             else:
  265                 self._data['matches'] = matches
  266 
  267     def setLastTime(self, value):
  268         if value > self._time:
  269             self._time = value
  270     
  271     def getLastTime(self):
  272         return self._time
  273 
  274     def getLastReset(self):
  275         return self._lastReset
  276 
  277     def setLastReset(self, value):
  278         self._lastReset = value
  279 
  280     @staticmethod
  281     def wrap(o):
  282         o.__class__ = FailTicket
  283         return o
  284 
  285 ##
  286 # Ban Ticket.
  287 #
  288 # This class extends the Ticket class. It is mainly used by the BanManager.
  289 
  290 class BanTicket(FailTicket):
  291     
  292     @staticmethod
  293     def wrap(o):
  294         o.__class__ = BanTicket
  295         return o