diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..3bffd79a --- /dev/null +++ b/.coveragerc @@ -0,0 +1,4 @@ + +[run] +branch = True +omit = /usr* diff --git a/.gitignore b/.gitignore index 6a0d5e64..1e3b2ec4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ *~ build +dist *.pyc +htmlcov +.coverage diff --git a/DEVELOP b/DEVELOP index 7a6a7b9b..09bf7277 100644 --- a/DEVELOP +++ b/DEVELOP @@ -24,14 +24,97 @@ Request feature. You can find more details on the Fail2Ban wiki Testing ======= -Existing tests can be run by executing `fail2ban-testcases`. +Existing tests can be run by executing `fail2ban-testcases`. This has options +like --log-level that will probably be useful. `fail2ban-testcases --help` for +full options. + +Test cases should cover all usual cases, all exception cases and all inside +/ outside boundary conditions. + +Test cases should cover all branches. The coverage tool will help identify +missing branches. Also see http://nedbatchelder.com/code/coverage/branch.html +for more details. + +Install the package python-coverage to visualise your test coverage. Run the +following (note: on Debian-based systems, the script is called +`python-coverage`): + +coverage run fail2ban-testcases +coverage html + +Then look at htmlcov/index.html and see how much coverage your test cases +exert over the codebase. Full coverage is a good thing however it may not be +complete. Try to ensure tests cover as many independant paths through the +code. + +Manual Execution. To run in a development environment do: + +./fail2ban-client -c config/ -s /tmp/f2b.sock -i start + +some quick commands: + +status +add test pyinotify +status test +set test addaction iptables +set test actionban iptables echo >> /tmp/ban +set test actionunban iptables echo >> /tmp/unban +get test actionban iptables +get test actionunban iptables +set test banip 192.168.2.2 +status test + -Documentation about creating tests (when tests are required and some guidelines -for creating good tests) will be added soon. Coding Standards -================ -Coming Soon. +================ + +Style +----- + +Please use tabs for now. Keep to 80 columns, at least for readable text. + +Tests +----- + +Add tests. They should test all the code you add in a meaning way. + +Coverage +-------- + +Test coverage should always increase as you add code. + +You may use "# pragma: no cover" in the code for branches of code that support +older versions on python. For all other uses of "pragma: no cover" or +"pragma: no branch" document the reason why its not covered. "I haven't written +a test case" isn't a sufficient reason. + +Documentation +------------- + +Ensure this documentation is up to date after changes. Also ensure that the man +pages still are accurate. Ensure that there is sufficient documentation for +your new features to be used. + +Bugs +---- + +Remove them and don't add any more. + +Git +--- + +Use the following tags in your commit messages: + +'ENH:' for enhancements +'BF:' for bug fixes +'DOC:' for documentation fixes + +Adding Actions +-------------- + +If you add an action.d/*.conf file also add a example in config/jail.conf +with enabled=false and maxretry=5 for ssh. Design @@ -127,12 +210,14 @@ FileContainer .__pos Keeps the position pointer + +dnsutils.py +~~~~~~~~~~~ + DNSUtils Utility class for DNS and IP handling - RF-Note: convert to functions within a separate submodule - filter*.py ~~~~~~~~~~ @@ -156,3 +241,29 @@ action.py ~~~~~~~~~ Takes care about executing start/check/ban/unban/stop commands + + +Releasing +========= + +Ensure the version is correct in ./common/version.py + +Add/finalize the corresponding entry in the ChangeLog + +# update man pages +(cd man ; ./generate-man ) + +git commit -m 'update man pages for release' man/* + +python setup.py check +python setup.py sdist +python setup.py bdist_rpm +python setup.py upload + +Run the following and update the wiki with output: + +python -c 'import common.protocol; common.protocol.printWiki()' + +email users and development list of release + +TODO notifying distributors etc. diff --git a/MANIFEST b/MANIFEST index eef145b6..bedfe560 100644 --- a/MANIFEST +++ b/MANIFEST @@ -3,6 +3,8 @@ ChangeLog TODO THANKS COPYING +DEVELOP +doc/run-rootless.txt fail2ban-client fail2ban-server fail2ban-testcases diff --git a/README b/README index 0a3d5117..e483a7fa 100644 --- a/README +++ b/README @@ -91,5 +91,5 @@ 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 -Fail2Ban; if not, write to the Free Software Foundation, Inc., 59 Temple Place, -Suite 330, Boston, MA 02111-1307 USA +Fail2Ban; if not, write to the Free Software Foundation, Inc., 51 Franklin +Street, Fifth Floor, Boston, MA 02110, USA diff --git a/TODO b/TODO index fc43dc2c..933134e9 100644 --- a/TODO +++ b/TODO @@ -13,6 +13,9 @@ Legend: # partially done * done +- Run tests though all filters/examples files - (see sshd example file) as unit + test + - Removed relative imports - Cleanup fail2ban-client and fail2ban-server. Move code to server/ and client/ diff --git a/client/fail2banreader.py b/client/fail2banreader.py index ee097bd6..6954b3bf 100644 --- a/client/fail2banreader.py +++ b/client/fail2banreader.py @@ -42,7 +42,8 @@ class Fail2banReader(ConfigReader): ConfigReader.read(self, "fail2ban") def getEarlyOptions(self): - opts = [["string", "socket", "/tmp/fail2ban.sock"]] + opts = [["string", "socket", "/tmp/fail2ban.sock"], + ["string", "pidfile", "/var/run/fail2ban/fail2ban.pid"]] return ConfigReader.getOptions(self, "Definition", opts) def getOptions(self): diff --git a/common/protocol.py b/common/protocol.py index de7c84a8..232fe2a2 100644 --- a/common/protocol.py +++ b/common/protocol.py @@ -40,6 +40,7 @@ protocol = [ ["stop", "stops all jails and terminate the server"], ["status", "gets the current status of the server"], ["ping", "tests if the server is alive"], +["help", "return this output"], ['', "LOGGING", ""], ["set loglevel ", "sets logging level to . 0 is minimal, 4 is debug"], ["get loglevel", "gets the logging level"], @@ -92,6 +93,7 @@ protocol = [ ["get actioncheck ", "gets the check command for the action for "], ["get actionban ", "gets the ban command for the action for "], ["get actionunban ", "gets the unban command for the action for "], +["get cinfo ", "gets the value for for the action for "], ] ## diff --git a/config/action.d/dshield.conf b/config/action.d/dshield.conf index 177329b2..c581af1c 100644 --- a/config/action.d/dshield.conf +++ b/config/action.d/dshield.conf @@ -116,7 +116,7 @@ actionunban = if [ -f .first ]; then port = ??? # Option: userid -# Notes.: Your DSheild user ID. Should be provided either in the jail config or +# Notes.: Your DShield user ID. Should be provided either in the jail config or # in a .local file. # Register at https://secure.dshield.org/register.html # Values: [ NUM ] Default: 0 @@ -124,13 +124,13 @@ port = ??? userid = 0 # Option: myip -# Notes.: TThe target IP for the attack (your public IP). Should be provided +# Notes.: The target IP for the attack (your public IP). Should be provided # either in the jail config or in a .local file unless your PUBLIC IP # is the first IP assigned to eth0 # Values: [ an IP address ] Default: Tries to find the IP address of eth0, # which in most cases will be a private IP, and therefore incorrect # -myip = `ip -4 addr show dev eth0 | grep inet | head -1 | sed -r 's/.*inet ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/'` +myip = `ip -4 addr show dev eth0 | grep inet | head -n 1 | sed -r 's/.*inet ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/'` # Option: protocol # Notes.: The protocol over which the attack is happening diff --git a/config/action.d/iptables-allports.conf b/config/action.d/iptables-allports.conf index f534fee9..c7f76c83 100644 --- a/config/action.d/iptables-allports.conf +++ b/config/action.d/iptables-allports.conf @@ -53,7 +53,7 @@ actionunban = iptables -D fail2ban- -s -j DROP [Init] -# Defaut name of the chain +# Default name of the chain # name = default diff --git a/config/action.d/iptables-ipset-proto4.conf b/config/action.d/iptables-ipset-proto4.conf index f7d03f67..665d35cf 100644 --- a/config/action.d/iptables-ipset-proto4.conf +++ b/config/action.d/iptables-ipset-proto4.conf @@ -53,7 +53,7 @@ actionunban = ipset --test fail2ban- && ipset --del fail2ban- < [Init] -# Defaut name of the ipset +# Default name of the ipset # name = default diff --git a/config/action.d/iptables-ipset-proto6.conf b/config/action.d/iptables-ipset-proto6.conf index 3352d63d..e4ceb0d0 100644 --- a/config/action.d/iptables-ipset-proto6.conf +++ b/config/action.d/iptables-ipset-proto6.conf @@ -53,7 +53,7 @@ actionunban = ipset del fail2ban- -exist [Init] -# Defaut name of the ipset +# Default name of the ipset # name = default diff --git a/config/action.d/iptables-multiport-log.conf b/config/action.d/iptables-multiport-log.conf index 9cdc4bab..0f4947dd 100644 --- a/config/action.d/iptables-multiport-log.conf +++ b/config/action.d/iptables-multiport-log.conf @@ -61,7 +61,7 @@ actionunban = iptables -D fail2ban- -s -j fail2ban--log [Init] -# Defaut name of the chain +# Default name of the chain # name = default diff --git a/config/action.d/iptables-multiport.conf b/config/action.d/iptables-multiport.conf index d062f74d..8b15ad86 100644 --- a/config/action.d/iptables-multiport.conf +++ b/config/action.d/iptables-multiport.conf @@ -51,7 +51,7 @@ actionunban = iptables -D fail2ban- -s -j DROP [Init] -# Defaut name of the chain +# Default name of the chain # name = default diff --git a/config/action.d/iptables-new.conf b/config/action.d/iptables-new.conf index 92bd9a55..64f54582 100644 --- a/config/action.d/iptables-new.conf +++ b/config/action.d/iptables-new.conf @@ -53,7 +53,7 @@ actionunban = iptables -D fail2ban- -s -j DROP [Init] -# Defaut name of the chain +# Default name of the chain # name = default diff --git a/config/action.d/iptables-xt_recent-echo.conf b/config/action.d/iptables-xt_recent-echo.conf index f3ac80b5..170fef07 100644 --- a/config/action.d/iptables-xt_recent-echo.conf +++ b/config/action.d/iptables-xt_recent-echo.conf @@ -11,7 +11,7 @@ # Notes.: command executed once at the start of Fail2Ban. # Values: CMD # -# Changing iptables rules requires root priviledges. If fail2ban is +# Changing iptables rules requires root privileges. If fail2ban is # configured to run as root, firewall setup can be performed by # fail2ban automatically. However, if fail2ban is configured to run as # a normal user, the configuration must be done by some other means @@ -65,7 +65,7 @@ actionunban = echo - > /proc/net/xt_recent/fail2ban- [Init] -# Defaut name of the chain +# Default name of the chain # name = default diff --git a/config/action.d/iptables.conf b/config/action.d/iptables.conf index a846f971..083065fc 100644 --- a/config/action.d/iptables.conf +++ b/config/action.d/iptables.conf @@ -51,7 +51,7 @@ actionunban = iptables -D fail2ban- -s -j DROP [Init] -# Defaut name of the chain +# Default name of the chain # name = default diff --git a/config/action.d/mail-whois-lines.conf b/config/action.d/mail-whois-lines.conf index 6d3343b6..1ace68f6 100644 --- a/config/action.d/mail-whois-lines.conf +++ b/config/action.d/mail-whois-lines.conf @@ -62,7 +62,7 @@ actionunban = [Init] -# Defaut name of the chain +# Default name of the chain # name = default diff --git a/config/action.d/mail-whois.conf b/config/action.d/mail-whois.conf index 9e6ec88e..1581c42c 100644 --- a/config/action.d/mail-whois.conf +++ b/config/action.d/mail-whois.conf @@ -59,7 +59,7 @@ actionunban = [Init] -# Defaut name of the chain +# Default name of the chain # name = default diff --git a/config/action.d/mail.conf b/config/action.d/mail.conf index 01f22ff8..02946b43 100644 --- a/config/action.d/mail.conf +++ b/config/action.d/mail.conf @@ -57,7 +57,7 @@ actionunban = [Init] -# Defaut name of the chain +# Default name of the chain # name = default diff --git a/config/action.d/mynetwatchman.conf b/config/action.d/mynetwatchman.conf index d4f8de1a..3ae3e6db 100644 --- a/config/action.d/mynetwatchman.conf +++ b/config/action.d/mynetwatchman.conf @@ -102,13 +102,13 @@ mnwlogin = mnwpass = # Option: myip -# Notes.: TThe target IP for the attack (your public IP). Should be overridden +# Notes.: The target IP for the attack (your public IP). Should be overridden # either in the jail config or in a .local file unless your PUBLIC IP # is the first IP assigned to eth0 # Values: [ an IP address ] Default: Tries to find the IP address of eth0, # which in most cases will be a private IP, and therefore incorrect # -myip = `ip -4 addr show dev eth0 | grep inet | head -1 | sed -r 's/.*inet ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/'` +myip = `ip -4 addr show dev eth0 | grep inet | head -n 1 | sed -r 's/.*inet ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/'` # Option: protocol # Notes.: The protocol over which the attack is happening diff --git a/config/action.d/route.conf b/config/action.d/route.conf new file mode 100644 index 00000000..ec940b74 --- /dev/null +++ b/config/action.d/route.conf @@ -0,0 +1,25 @@ +# Fail2Ban configuration file +# +# Author: Michael Gebetsroither +# +# This is for blocking whole hosts through blackhole routes. +# +# PRO: +# - Works on all kernel versions and as no compatibility problems (back to debian lenny and WAY further). +# - It's FAST for very large numbers of blocked ips. +# - It's FAST because it Blocks traffic before it enters common iptables chains used for filtering. +# - It's per host, ideal as action against ssh password bruteforcing to block further attack attempts. +# - No additional software required beside iproute/iproute2 +# +# CON: +# - Blocking is per IP and NOT per service, but ideal as action against ssh password bruteforcing hosts + +[Definition] +actionban = ip route add +actionunban = ip route del + +# Type of blocking +# +# Type can be blackhole, unreachable and prohibit. Unreachable and prohibit correspond to the ICMP reject messages. + +type = blackhole diff --git a/config/action.d/sendmail-buffered.conf b/config/action.d/sendmail-buffered.conf index 25a23b78..80f71374 100644 --- a/config/action.d/sendmail-buffered.conf +++ b/config/action.d/sendmail-buffered.conf @@ -83,7 +83,7 @@ actionunban = [Init] -# Defaut name of the chain +# Default name of the chain # name = default diff --git a/config/action.d/sendmail-whois-lines.conf b/config/action.d/sendmail-whois-lines.conf index d1e6e40f..dfbf9ff8 100644 --- a/config/action.d/sendmail-whois-lines.conf +++ b/config/action.d/sendmail-whois-lines.conf @@ -57,7 +57,7 @@ actionban = printf %%b "Subject: [Fail2Ban] : banned Here are more information about :\n `/usr/bin/whois `\n\n Lines containing IP: in \n - `/bin/grep '\<\>' `\n\n + `grep '\<\>' `\n\n Regards,\n Fail2Ban" | /usr/sbin/sendmail -f @@ -73,7 +73,7 @@ actionunban = [Init] -# Defaut name of the chain +# Default name of the chain # name = default diff --git a/config/action.d/sendmail-whois.conf b/config/action.d/sendmail-whois.conf index 363c3398..e6a15fb5 100644 --- a/config/action.d/sendmail-whois.conf +++ b/config/action.d/sendmail-whois.conf @@ -71,7 +71,7 @@ actionunban = [Init] -# Defaut name of the chain +# Default name of the chain # name = default diff --git a/config/action.d/sendmail.conf b/config/action.d/sendmail.conf index bdc2a3b6..5bb75575 100644 --- a/config/action.d/sendmail.conf +++ b/config/action.d/sendmail.conf @@ -69,7 +69,7 @@ actionunban = [Init] -# Defaut name of the chain +# Default name of the chain # name = default diff --git a/config/fail2ban.conf b/config/fail2ban.conf index f2f1b215..e759513b 100644 --- a/config/fail2ban.conf +++ b/config/fail2ban.conf @@ -40,3 +40,10 @@ logtarget = /var/log/fail2ban.log # socket = /var/run/fail2ban/fail2ban.sock +# Option: pidfile +# Notes.: Set the PID file. This is used to store the process ID of the +# fail2ban server. +# Values: FILE Default: /var/run/fail2ban/fail2ban.sock +# +pidfile = /var/run/fail2ban/fail2ban.pid + diff --git a/config/filter.d/apache-badbots.conf b/config/filter.d/apache-badbots.conf index 1d70bb0e..1c60676d 100644 --- a/config/filter.d/apache-badbots.conf +++ b/config/filter.d/apache-badbots.conf @@ -16,7 +16,7 @@ badbots = atSpider/1\.0|autoemailspider|China Local Browse 2\.6|ContentSmartz|Da # Option: failregex # Notes.: Regexp to catch known spambots and software alike. Please verify # that it is your intent to block IPs which were driven by -# abovementioned bots. +# above mentioned bots. # Values: TEXT # failregex = ^ -.*"(GET|POST).*HTTP.*"(?:%(badbots)s|%(badbotscustom)s)"$ diff --git a/config/jail.conf b/config/jail.conf index 1817ebd5..8bb1a6b6 100644 --- a/config/jail.conf +++ b/config/jail.conf @@ -101,6 +101,17 @@ action = hostsdeny ignoreregex = for myuser from logpath = /var/log/sshd.log +# Here we use blackhole routes for not requiring any additional kernel support +# to store large volumes of banned IPs + +[ssh-route] + +enabled = false +filter = sshd +action = route +logpath = /var/log/sshd.log +maxretry = 5 + # Here we use a combination of Netfilter/Iptables and IPsets # for storing large volumes of banned IPs # @@ -230,7 +241,7 @@ logpath = /var/log/lighttpd/error.log maxretry = 2 # Same as above for mod_auth -# It catches wrong authentifications +# It catches wrong authentications [lighttpd-auth] diff --git a/doc/run-rootless.txt b/doc/run-rootless.txt index 85a8f766..5edf6ef6 100644 --- a/doc/run-rootless.txt +++ b/doc/run-rootless.txt @@ -1,7 +1,7 @@ -Fail2ban normally requires root priviledges to insert iptables rules +Fail2ban normally requires root privileges to insert iptables rules through calls to /sbin/iptables and also to read the logfiles. -Fail2ban can run as an unpriviledged user provided that those two -capabilites are preserved. The idea is to run fail2ban as a normal +Fail2ban can run as an unprivileged user provided that those two +capabilities are preserved. The idea is to run fail2ban as a normal user (e.g. fail2ban) who belongs to a group which is allowed to read logfiles. The user should also be allowed to write to /proc/net/xt_recent/fail2ban- (name is specified in the iptables @@ -20,14 +20,14 @@ Another way to use xt_recent is by inserting the rules by writing to action. Files in /proc/net/xt_recent/ are protected by normal filesystem rules, so can be chown'ed and chmod'ed to be writable by a certain user. After the necessary iptables rules are inserted (which -requires root priviledges), blacklisting can be perfomed by an -unpriviledged user. +requires root privileges), blacklisting can be performed by an +unprivileged user. Using fail2ban with xt_recent allows smarter filtering than normal iptables rules with the xt_recent module can provide. The disadvantage is that fail2ban cannot perform the setup by itself, -which would require the priviledge to call /sbin/iptables, and it must +which would require the privilege to call /sbin/iptables, and it must be done through other means. The primary advantage is obvious: it's generally better to run @@ -46,7 +46,7 @@ some user and thus allow delisting IPs by helper administrators without the ability to mess up other iptables rules. The xt_recent-echo jail can be used under the root user without -further configuration. To run not as root, futher setup is necessary: +further configuration. To run not as root, further setup is necessary: - Create user: diff --git a/fail2ban-client b/fail2ban-client index 13d018e6..061208dd 100755 --- a/fail2ban-client +++ b/fail2ban-client @@ -62,6 +62,7 @@ class Fail2banClient: self.__conf["verbose"] = 1 self.__conf["interactive"] = False self.__conf["socket"] = None + self.__conf["pidfile"] = None def dispVersion(self): print "Fail2Ban v" + version @@ -84,6 +85,7 @@ class Fail2banClient: print "Options:" print " -c configuration directory" print " -s socket path" + print " -p pidfile path" print " -d dump configuration. For debugging" print " -i interactive mode" print " -v increase verbosity" @@ -119,6 +121,8 @@ class Fail2banClient: self.__conf["conf"] = opt[1] elif opt[0] == "-s": self.__conf["socket"] = opt[1] + elif opt[0] == "-p": + self.__conf["pidfile"] = opt[1] elif opt[0] == "-d": self.__conf["dump"] = True elif opt[0] == "-v": @@ -130,11 +134,11 @@ class Fail2banClient: elif opt[0] == "-i": self.__conf["interactive"] = True elif opt[0] in ["-h", "--help"]: - self.dispUsage() - sys.exit(0) - elif opt[0] in ["-V", "--version"]: - self.dispVersion() - sys.exit(0) + self.dispUsage() + sys.exit(0) + elif opt[0] in ["-V", "--version"]: + self.dispVersion() + sys.exit(0) def __ping(self): return self.__processCmd([["ping"]], False) @@ -181,8 +185,21 @@ class Fail2banClient: # Do not continue if configuration is not 100% valid if not ret: return False + # verify that directory for the socket file exists + socket_dir = os.path.dirname(self.__conf["socket"]) + if not os.path.exists(socket_dir): + logSys.error( + "There is no directory %s to contain the socket file %s." + % (socket_dir, self.__conf["socket"])) + return False + if not os.access(socket_dir, os.W_OK | os.X_OK): + logSys.error( + "Directory %s exists but not accessible for writing" + % (socket_dir,)) + return False # Start the server self.__startServerAsync(self.__conf["socket"], + self.__conf["pidfile"], self.__conf["force"]) try: # Wait for the server to start @@ -191,10 +208,10 @@ class Fail2banClient: self.__processCmd(self.__stream, False) return True except ServerExecutionException: - logSys.error("Could not start server. Maybe an old " + - "socket file is still present. Try to " + - "remove " + self.__conf["socket"] + ". If " + - "you used fail2ban-client to start the " + + logSys.error("Could not start server. Maybe an old " + "socket file is still present. Try to " + "remove " + self.__conf["socket"] + ". If " + "you used fail2ban-client to start the " "server, adding the -x option will do it") return False elif len(cmd) == 1 and cmd[0] == "reload": @@ -231,7 +248,7 @@ class Fail2banClient: # # Start the Fail2ban server in daemon mode. - def __startServerAsync(self, socket, force = False): + def __startServerAsync(self, socket, pidfile, force = False): # Forks the current process. pid = os.fork() if pid == 0: @@ -242,22 +259,26 @@ class Fail2banClient: # Set the socket path. args.append("-s") args.append(socket) + # Set the pidfile + args.append("-p") + args.append(pidfile) # Force the execution if needed. if force: args.append("-x") try: # Use the current directory. exe = os.path.abspath(os.path.join(sys.path[0], self.SERVER)) + logSys.debug("Starting %r with args %r" % (exe, args)) os.execv(exe, args) except OSError: try: # Use the PATH env. + logSys.warning("Initial start attempt failed. Starting %r with the same args" % (self.SERVER,)) os.execvp(self.SERVER, args) except OSError: - print "Could not find %s" % self.SERVER + logSys.error("Could not start %s" % self.SERVER) os.exit(-1) - - + def __waitOnServer(self): # Wait for the server to start cnt = 0 @@ -276,7 +297,7 @@ class Fail2banClient: delta = -1 elif pos < 2: delta = 1 - # The server has 30 secondes to start. + # The server has 30 seconds to start. if cnt >= 300: if self.__conf["verbose"] > 1: sys.stdout.write('\n') @@ -297,7 +318,7 @@ class Fail2banClient: # Reads the command line options. try: - cmdOpts = 'hc:s:xdviqV' + cmdOpts = 'hc:s:p:xdviqV' cmdLongOpts = ['help', 'version'] optList, args = getopt.getopt(self.__argv[1:], cmdOpts, cmdLongOpts) except getopt.GetoptError: @@ -328,9 +349,11 @@ class Fail2banClient: # Set socket path self.__configurator.readEarly() - socket = self.__configurator.getEarlyOptions() + conf = self.__configurator.getEarlyOptions() if self.__conf["socket"] == None: - self.__conf["socket"] = socket["socket"] + self.__conf["socket"] = conf["socket"] + if self.__conf["pidfile"] == None: + self.__conf["pidfile"] = conf["pidfile"] logSys.info("Using socket file " + self.__conf["socket"]) if self.__conf["dump"]: @@ -357,7 +380,9 @@ class Fail2banClient: if cmd == "exit" or cmd == "quit": # Exit return True - if not cmd == "": + if cmd == "help": + self.dispUsage() + elif not cmd == "": self.__processCommand(shlex.split(cmd)) except (EOFError, KeyboardInterrupt): print @@ -395,7 +420,7 @@ class Fail2banClient: class ServerExecutionException(Exception): pass -if __name__ == "__main__": +if __name__ == "__main__": # pragma: no cover - can't test main client = Fail2banClient() # Exit with correct return value if client.start(sys.argv): diff --git a/fail2ban-server b/fail2ban-server index 0f3410c9..81db58bd 100755 --- a/fail2ban-server +++ b/fail2ban-server @@ -54,6 +54,7 @@ class Fail2banServer: self.__conf["background"] = True self.__conf["force"] = False self.__conf["socket"] = "/var/run/fail2ban/fail2ban.sock" + self.__conf["pidfile"] = "/var/run/fail2ban/fail2ban.pid" def dispVersion(self): print "Fail2Ban v" + version @@ -81,6 +82,7 @@ class Fail2banServer: print " -b start in background" print " -f start in foreground" print " -s socket path" + print " -p pidfile path" print " -x force execution of the server (remove socket file)" print " -h, --help display this help message" print " -V, --version print the version" @@ -97,6 +99,8 @@ class Fail2banServer: self.__conf["background"] = False if opt[0] == "-s": self.__conf["socket"] = opt[1] + if opt[0] == "-p": + self.__conf["pidfile"] = opt[1] if opt[0] == "-x": self.__conf["force"] = True if opt[0] in ["-h", "--help"]: @@ -112,7 +116,7 @@ class Fail2banServer: # Reads the command line options. try: - cmdOpts = 'bfs:xhV' + cmdOpts = 'bfs:p:xhV' cmdLongOpts = ['help', 'version'] optList, args = getopt.getopt(self.__argv[1:], cmdOpts, cmdLongOpts) except getopt.GetoptError: @@ -123,7 +127,9 @@ class Fail2banServer: try: self.__server = Server(self.__conf["background"]) - self.__server.start(self.__conf["socket"], self.__conf["force"]) + self.__server.start(self.__conf["socket"], + self.__conf["pidfile"], + self.__conf["force"]) return True except Exception, e: logSys.exception(e) diff --git a/fail2ban-testcases b/fail2ban-testcases index afc037f7..3b38d6b6 100755 --- a/fail2ban-testcases +++ b/fail2ban-testcases @@ -77,10 +77,10 @@ verbosity = {'debug': 3, 'fatal': 0, None: 1}[opts.log_level] -if opts.log_level is not None: +if opts.log_level is not None: # pragma: no cover # so we had explicit settings logSys.setLevel(getattr(logging, opts.log_level.upper())) -else: +else: # pragma: no cover # suppress the logging but it would leave unittests' progress dots # ticking, unless like with '-l fatal' which would be silent # unless error occurs @@ -89,9 +89,9 @@ else: # Add the default logging handler stdout = logging.StreamHandler(sys.stdout) # Custom log format for the verbose tests runs -if verbosity > 1: +if verbosity > 1: # pragma: no cover stdout.setFormatter(logging.Formatter(' %(asctime)-15s %(thread)s %(message)s')) -else: +else: # pragma: no cover # just prefix with the space stdout.setFormatter(logging.Formatter(' %(message)s')) logSys.addHandler(stdout) @@ -99,7 +99,7 @@ logSys.addHandler(stdout) # # Let know the version # -if not opts.log_level or opts.log_level != 'fatal': +if not opts.log_level or opts.log_level != 'fatal': # pragma: no cover print "Fail2ban %s test suite. Python %s. Please wait..." \ % (version, str(sys.version).replace('\n', '')) @@ -107,9 +107,9 @@ if not opts.log_level or opts.log_level != 'fatal': # # Gather the tests # -if not len(regexps): +if not len(regexps): # pragma: no cover tests = unittest.TestSuite() -else: +else: # pragma: no cover import re class FilteredTestSuite(unittest.TestSuite): _regexps = [re.compile(r) for r in regexps] @@ -124,7 +124,7 @@ else: # Server #tests.addTest(unittest.makeSuite(servertestcase.StartStop)) -#tests.addTest(unittest.makeSuite(servertestcase.Transmitter)) +tests.addTest(unittest.makeSuite(servertestcase.Transmitter)) tests.addTest(unittest.makeSuite(actiontestcase.ExecuteAction)) # FailManager tests.addTest(unittest.makeSuite(failmanagertestcase.AddFailure)) @@ -160,13 +160,13 @@ filters = [FilterPoll] # always available try: from server.filtergamin import FilterGamin filters.append(FilterGamin) -except Exception, e: +except Exception, e: # pragma: no cover print "I: Skipping gamin backend testing. Got exception '%s'" % e try: from server.filterpyinotify import FilterPyinotify filters.append(FilterPyinotify) -except Exception, e: +except Exception, e: # pragma: no cover print "I: Skipping pyinotify backend testing. Got exception '%s'" % e for Filter_ in filters: @@ -190,7 +190,7 @@ try: tests_results = testRunner.run(tests) -finally: +finally: # pragma: no cover # Just for the sake of it reset the TZ # yoh: move all this into setup/teardown methods within tests os.environ.pop('TZ') @@ -198,5 +198,5 @@ finally: os.environ['TZ'] = old_TZ time.tzset() -if not tests_results.wasSuccessful(): +if not tests_results.wasSuccessful(): # pragma: no cover sys.exit(1) diff --git a/files/cacti/README b/files/cacti/README index 80c97ce9..73ceb3bd 100644 --- a/files/cacti/README +++ b/files/cacti/README @@ -49,5 +49,5 @@ details. You should have received a copy of the GNU General Public License along with Fail2Ban; if not, write to the Free -Software Foundation, Inc., 59 Temple Place, Suite 330, -Boston, MA 02111-1307 USA +Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110, USA diff --git a/man/fail2ban-client.1 b/man/fail2ban-client.1 index 1bbddf09..431e690f 100644 --- a/man/fail2ban-client.1 +++ b/man/fail2ban-client.1 @@ -1,12 +1,12 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36. -.TH FAIL2BAN-CLIENT "1" "March 2008" "fail2ban-client v0.8.2" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.10. +.TH FAIL2BAN-CLIENT "1" "March 2013" "fail2ban-client v0.8.8" "User Commands" .SH NAME fail2ban-client \- configure and control the server .SH SYNOPSIS .B fail2ban-client [\fIOPTIONS\fR] \fI\fR .SH DESCRIPTION -Fail2Ban v0.8.2 reads log file that contains password failure report +Fail2Ban v0.8.8 reads log file that contains password failure report and bans the corresponding IP addresses using firewall rules. .SH OPTIONS .TP @@ -16,6 +16,9 @@ configuration directory \fB\-s\fR socket path .TP +\fB\-p\fR +pidfile path +.TP \fB\-d\fR dump configuration. For debugging .TP @@ -110,7 +113,7 @@ adds to the monitoring list of .TP \fBset dellogpath \fR -removes to the monitoring +removes from the monitoring list of .TP \fBset addfailregex \fR @@ -140,6 +143,15 @@ back for sets the number of seconds