-
-
-
-
- |
-
- |
- |
- 1 |
- # This file is part of Fail2Ban. |
-
-
- 2 |
- # |
-
-
- 3 |
- # Fail2Ban is free software; you can redistribute it and/or modify |
-
-
- 4 |
- # it under the terms of the GNU General Public License as published by |
-
-
- 5 |
- # the Free Software Foundation; either version 2 of the License, or |
-
-
- 6 |
- # (at your option) any later version. |
-
-
- 7 |
- # |
-
-
- 8 |
- # Fail2Ban is distributed in the hope that it will be useful, |
-
-
- 9 |
- # but WITHOUT ANY WARRANTY; without even the implied warranty of |
-
-
- 10 |
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
-
-
- 11 |
- # GNU General Public License for more details. |
-
-
- 12 |
- # |
-
-
- 13 |
- # You should have received a copy of the GNU General Public License |
-
-
- 14 |
- # along with Fail2Ban; if not, write to the Free Software |
-
-
- 15 |
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
-
-
- 16 |
- |
-
-
- 17 |
- # Author: Jonathan G. Underwood |
-
-
- 18 |
- # |
-
-
- 19 |
- # $Revision$ |
-
-
- 20 |
- |
-
-
- 21 |
- __author__ = "Jonathan G. Underwood" |
-
-
- 22 |
- __version__ = "$Revision$" |
-
-
- 23 |
- __date__ = "$Date$" |
-
-
- 24 |
- __copyright__ = "Copyright (c) 2010 Jonathan G. Underwood" |
-
-
- 25 |
- __license__ = "GPL" |
-
-
- 26 |
- |
-
-
- 27 |
- from failmanager import FailManagerEmpty |
-
-
- 28 |
- from filter import FileFilter |
-
-
- 29 |
- from mytime import MyTime |
-
-
- 30 |
- |
-
-
- 31 |
- import time, logging |
-
-
- 32 |
- |
-
-
- 33 |
- import pyinotify |
-
-
- 34 |
- from pyinotify import ProcessEvent, WatchManager, Notifier |
-
-
- 35 |
- |
-
-
- 36 |
- # Gets the instance of the logger. |
-
-
- 37 |
- logSys = logging.getLogger("fail2ban.filter") |
-
-
- 38 |
- |
-
-
- 39 |
- ## |
-
-
- 40 |
- # Log reader class. |
-
-
- 41 |
- # |
-
-
- 42 |
- # This class reads a log file and detects login failures or anything else |
-
-
- 43 |
- # that matches a given regular expression. This class is instanciated by |
-
-
- 44 |
- # a Jail object. |
-
-
- 45 |
- |
-
-
- 46 |
- class FilterInotify(ProcessEvent, FileFilter): |
-
-
- 47 |
- |
-
-
- 48 |
- ## |
-
-
- 49 |
- # Constructor. |
-
-
- 50 |
- # |
-
-
- 51 |
- # Initialize the filter object with default values. |
-
-
- 52 |
- # @param jail the jail object |
-
-
- 53 |
- |
-
-
- 54 |
- # Note that according to the pyinotify documentation we shouldn't |
-
-
- 55 |
- # define an __init__ function, but define a my_init function which is |
-
-
- 56 |
- # called by ProcessEvent.__init__. However, that approach appears not |
-
-
- 57 |
- # to work here and so we define __init__ and call |
-
-
- 58 |
- # ProcessEvent.__init__ from here. |
-
-
- 59 |
- def __init__(self, jail): |
-
-
- 60 |
- FileFilter.__init__(self, jail) |
-
-
- 61 |
- ProcessEvent.__init__(self) |
-
-
- 62 |
- self.__monitor = WatchManager() |
-
-
- 63 |
- self.__notifier = Notifier(self.__monitor, self) |
-
-
- 64 |
- self.__mask = pyinotify.IN_MODIFY | pyinotify.IN_CREATE |
-
-
- 65 |
- |
-
-
- 66 |
- ## |
-
-
- 67 |
- # Event handling functions used by pyinotify.ProcessEvent |
-
-
- 68 |
- # instance. These simply call the __handleMod method. |
-
-
- 69 |
- # @event an event object |
-
-
- 70 |
- |
-
-
- 71 |
- def process_IN_MODIFY(self, event): |
-
-
- 72 |
- logSys.debug("process_IN_MODIFY called") |
-
-
- 73 |
- self.__handleMod(event) |
-
-
- 74 |
- |
-
-
- 75 |
- def process_IN_CREATE(self, event): |
-
-
- 76 |
- logSys.debug("process_IN_CREATE called") |
-
-
- 77 |
- self.__handleMod(event) |
-
-
- 78 |
- |
-
-
- 79 |
- ## |
-
-
- 80 |
- # This method handles all modified file events |
-
-
- 81 |
- # @event an event object |
-
-
- 82 |
- |
-
-
- 83 |
- def __handleMod(self, event): |
-
-
- 84 |
- self.getFailures(event.path) |
-
-
- 85 |
- try: |
-
-
- 86 |
- while True: |
-
-
- 87 |
- ticket = self.failManager.toBan() |
-
-
- 88 |
- self.jail.putFailTicket(ticket) |
-
-
- 89 |
- except FailManagerEmpty: |
-
-
- 90 |
- self.failManager.cleanup(MyTime.time()) |
-
-
- 91 |
- self.dateDetector.sortTemplate() |
-
-
- 92 |
- |
-
-
- 93 |
- ## |
-
-
- 94 |
- # Add a log file path |
-
-
- 95 |
- # |
-
-
- 96 |
- # @param path log file path |
-
-
- 97 |
- |
-
-
- 98 |
- def addLogPath(self, path, tail = False): |
-
-
- 99 |
- if self.containsLogPath(path): |
-
-
- 100 |
- logSys.error(path + " already exists") |
-
-
- 101 |
- else: |
-
-
- 102 |
- wd = self.__monitor.add_watch(path, self.__mask) |
-
-
- 103 |
- if wd[path] > 0: |
-
-
- 104 |
- FileFilter.addLogPath(self, path, tail) |
-
-
- 105 |
- logSys.info("Added logfile = %s" % path) |
-
-
- 106 |
- else: |
-
-
- 107 |
- logSys.error("Failed to add an inotify watch for logfile = %s" % path) |
-
-
- 108 |
- |
-
-
- 109 |
- ## |
-
-
- 110 |
- # Delete a log path |
-
-
- 111 |
- # |
-
-
- 112 |
- # @param path the log file to delete |
-
-
- 113 |
- |
-
-
- 114 |
- def delLogPath(self, path): |
-
-
- 115 |
- if not self.containsLogPath(path): |
-
-
- 116 |
- logSys.error(path + " is not monitored") |
-
-
- 117 |
- else: |
-
-
- 118 |
- rd = self.__monitor.rm_watch(self.__monitor.get_wd(path)) |
-
-
- 119 |
- if rd[path]: |
-
-
- 120 |
- FileFilter.delLogPath(self, path) |
-
-
- 121 |
- logSys.info("Removed logfile = %s" % path) |
-
-
- 122 |
- else: |
-
-
- 123 |
- logSys.error("Failed to remove inotify watch for logfile = %s" % path) |
-
-
- 124 |
- |
-
-
- 125 |
- ## |
-
-
- 126 |
- # Main loop. |
-
-
- 127 |
- # |
-
-
- 128 |
- # This function is the main loop of the thread. It checks if the |
-
-
- 129 |
- # file has been modified and looks for failures. |
-
-
- 130 |
- # @return True when the thread exits nicely |
-
-
- 131 |
- |
-
-
- 132 |
- def run(self): |
-
-
- 133 |
- self.setActive(True) |
-
-
- 134 |
- while self._isActive(): |
-
-
- 135 |
- if not self.getIdle(): |
-
-
- 136 |
- # We cannot block here because we want to be able to |
-
-
- 137 |
- # exit. __notifier.check_events will block for |
-
-
- 138 |
- # timeout milliseconds. |
-
-
- 139 |
- if self.__notifier.check_events(timeout=10): |
-
-
- 140 |
- self.__notifier.read_events() |
-
-
- 141 |
- self.__notifier.process_events() |
-
-
- 142 |
- time.sleep(self.getSleepTime()) |
-
-
- 143 |
- else: |
-
-
- 144 |
- time.sleep(self.getSleepTime()) |
-
-
- 145 |
- |
-
-
- 146 |
- # Cleanup when shutting down |
-
-
- 147 |
- for wd in self.watchd.keys(): |
-
-
- 148 |
- self.__monitor.rm_watch(wd) |
-
-
- 149 |
- del self.__monitor |
-
-
- 150 |
- self.__notifier.stop() |
-
-
- 151 |
- del self.__notifier |
-
-
- 152 |
- |
-
-
- 153 |
- logSys.debug(self.jail.getName() + ": filter terminated") |
-
-
- 154 |
- return True |
-
-
- 155 |
- |
-
-
- 156 |
- |
-
-
- 157 |
- |
-
-
-