From 884f708bd7f4b48c90503752d927975ba10dafbc Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 09:07:28 -0400 Subject: [PATCH 01/22] fail2ban/files: rename "gentoo" files to "openrc". We ship a service script and configuration file for "gentoo" that are actually more generally applicable: they work on any system where OpenRC is used. This commit simply renames the files from "gentoo" to "openrc" to reflect the fact that they are in no way Gentoo-specific. --- MANIFEST | 4 ++-- files/{gentoo-confd => fail2ban-openrc.conf} | 0 files/{gentoo-initd => fail2ban-openrc.init} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename files/{gentoo-confd => fail2ban-openrc.conf} (100%) rename files/{gentoo-initd => fail2ban-openrc.init} (100%) diff --git a/MANIFEST b/MANIFEST index 3ea2816b..ca9be123 100644 --- a/MANIFEST +++ b/MANIFEST @@ -375,8 +375,8 @@ files/fail2ban.service.in files/fail2ban-tmpfiles.conf files/fail2ban.upstart files/gen_badbots -files/gentoo-confd -files/gentoo-initd +files/fail2ban-openrc.conf +files/fail2ban-openrc.init files/ipmasq-ZZZzzz_fail2ban.rul files/logwatch/fail2ban files/logwatch/fail2ban-0.8.log diff --git a/files/gentoo-confd b/files/fail2ban-openrc.conf similarity index 100% rename from files/gentoo-confd rename to files/fail2ban-openrc.conf diff --git a/files/gentoo-initd b/files/fail2ban-openrc.init similarity index 100% rename from files/gentoo-initd rename to files/fail2ban-openrc.init From 1cec3d05b8a052423a7ef4f8205c9d63b1ce9b07 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 09:11:53 -0400 Subject: [PATCH 02/22] files/fail2ban-openrc.conf: remove hard-coded paths. There were two paths mentioned in comments in the fail2ban OpenRC conf file, but those paths aren't guaranteed to be correct (until/unless we integrate the conf file with the build system). The first comment referenced the physical location of the associated init script, and in my opinion is not useful to an end user in the first place. It has been removed: OpenRC users know what this file is for, there's no reason to repeat it in a comment. The second comment contained an absolute path to fail2ban-client, and I've removed the leading path components because "fail2ban-client" is generally run from your $PATH. --- files/fail2ban-openrc.conf | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/files/fail2ban-openrc.conf b/files/fail2ban-openrc.conf index 00d19f8b..1c589763 100644 --- a/files/fail2ban-openrc.conf +++ b/files/fail2ban-openrc.conf @@ -1,6 +1,4 @@ -# Config file for /etc/init.d/fail2ban -# -# For information on options, see "/usr/bin/fail2ban-client -h". +# For available options, plase run "fail2ban-client -h". FAIL2BAN_OPTIONS="" From eb58e90ba9ccd049fae8bd92d8f828df6fdb287e Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 09:17:29 -0400 Subject: [PATCH 03/22] files/fail2ban-openrc.conf: remove a commented example setting. Our OpenRC conf file already tells users how to find the available options that can be placed in the FAIL2BAN_OPTIONS variable, so having a specific example of, FAIL2BAN_OPTIONS="-x" doesn't provide much more information. In fact, it makes you wonder why it's there in the first place: does the init script have some kind of problem with stale sockets? It used to, but that problem has been fixed. This commit removes the redundant example. --- files/fail2ban-openrc.conf | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/files/fail2ban-openrc.conf b/files/fail2ban-openrc.conf index 1c589763..1a2450e2 100644 --- a/files/fail2ban-openrc.conf +++ b/files/fail2ban-openrc.conf @@ -1,6 +1,2 @@ # For available options, plase run "fail2ban-client -h". - -FAIL2BAN_OPTIONS="" - -# Force execution of the server even if the socket already exists: -#FAIL2BAN_OPTIONS="-x" +#FAIL2BAN_OPTIONS="" From 64ec399542f20582090a69b77f4c5b90f7b41019 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 12:59:18 -0400 Subject: [PATCH 04/22] files/fail2ban-openrc.init: drop "need net" dependency. The "need net" dependency in our OpenRC service script was incorrect: the fail2ban service does not need a working WAN to function. This issue is well-documented and is covered in the OpenRC Service Script Guide, currently located at https://github.com/OpenRC/openrc/blob/master/service-script-guide.md --- files/fail2ban-openrc.init | 1 - 1 file changed, 1 deletion(-) diff --git a/files/fail2ban-openrc.init b/files/fail2ban-openrc.init index 0fb157cd..69025499 100755 --- a/files/fail2ban-openrc.init +++ b/files/fail2ban-openrc.init @@ -26,7 +26,6 @@ extra_started_commands="reload showlog" FAIL2BAN="/usr/bin/fail2ban-client ${FAIL2BAN_OPTIONS}" depend() { - need net need logger after iptables } From af24c52558296e52e90cb55fad449b2bf9e996c6 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 13:05:11 -0400 Subject: [PATCH 05/22] files/fail2ban-openrc.init: change "need logger" dependency to "use logger". Our OpenRC service script contained a "need logger" dependency, which meant that the life cycle of the fail2ban service was tied to that of the system logger service. That isn't quite correct: fail2ban functions fine even if the system logger is stopped: 1. fail2ban is capable of analyzing non-syslog log files. 2. Even if fail2ban is solely analyzing syslog files, we don't want to stop the fail2ban service simply because syslog was stopped -- fail2ban just won't see any new log lines until syslog is started again. This commit changes the "need net" dependency to "use net", which will still attempt to start the system logger service, but which won't kill fail2ban if the system logger is ever stopped. --- files/fail2ban-openrc.init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/fail2ban-openrc.init b/files/fail2ban-openrc.init index 69025499..138bff30 100755 --- a/files/fail2ban-openrc.init +++ b/files/fail2ban-openrc.init @@ -26,7 +26,7 @@ extra_started_commands="reload showlog" FAIL2BAN="/usr/bin/fail2ban-client ${FAIL2BAN_OPTIONS}" depend() { - need logger + use logger after iptables } From bc4a742e32f610879fcdb1af7677e46007ac0682 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 13:13:13 -0400 Subject: [PATCH 06/22] files/fail2ban-openrc.init: replace FAIL2BAN with standard OpenRC variables. The FAIL2BAN variable in our OpenRC service script was a combination of two standard OpenRC variables, "command" and "command_args". This commit simply replaces the custom variable with the two standard ones. This will aid future simplifications of the service script. --- files/fail2ban-openrc.init | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/files/fail2ban-openrc.init b/files/fail2ban-openrc.init index 138bff30..1374da3d 100755 --- a/files/fail2ban-openrc.init +++ b/files/fail2ban-openrc.init @@ -23,7 +23,8 @@ description_reload="reload configuration" description_showlog="show fail2ban logs" extra_started_commands="reload showlog" -FAIL2BAN="/usr/bin/fail2ban-client ${FAIL2BAN_OPTIONS}" +command="/usr/bin/fail2ban-client" +command_args="${FAIL2BAN_OPTIONS}" depend() { use logger @@ -37,20 +38,20 @@ start() { # bug 347477 rm -f /var/run/fail2ban/fail2ban.sock || return 1 start-stop-daemon --start --pidfile /var/run/fail2ban/fail2ban.pid \ - -- ${FAIL2BAN} start + -- ${command} ${command_args} start eend $? "Failed to start fail2ban" } stop() { ebegin "Stopping fail2ban" start-stop-daemon --stop --pidfile /var/run/fail2ban/fail2ban.pid --retry 30 \ - -- ${FAIL2BAN} stop + -- ${command} ${command_args} stop eend $? "Failed to stop fail2ban" } reload() { ebegin "Reloading fail2ban" - ${FAIL2BAN} reload + ${command} ${command_args} reload eend $? "Failed to reload fail2ban" } From 115024d14a0b1a5a4b96175712f257b408883f38 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 13:15:44 -0400 Subject: [PATCH 07/22] files/fail2ban-openrc.init: use a variable for the pid file location. OpenRC has a special variable "pidfile" that should be used to store the location of the daemon's PID file. This commit replaces two instances of said location with one variable. --- files/fail2ban-openrc.init | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/files/fail2ban-openrc.init b/files/fail2ban-openrc.init index 1374da3d..9969a3e0 100755 --- a/files/fail2ban-openrc.init +++ b/files/fail2ban-openrc.init @@ -25,6 +25,7 @@ extra_started_commands="reload showlog" command="/usr/bin/fail2ban-client" command_args="${FAIL2BAN_OPTIONS}" +pidfile="/run/${RC_SVCNAME}/${RC_SVCNAME}.pid" depend() { use logger @@ -37,14 +38,14 @@ start() { # remove stalled sock file after system crash # bug 347477 rm -f /var/run/fail2ban/fail2ban.sock || return 1 - start-stop-daemon --start --pidfile /var/run/fail2ban/fail2ban.pid \ + start-stop-daemon --start --pidfile "${pidfile}" \ -- ${command} ${command_args} start eend $? "Failed to start fail2ban" } stop() { ebegin "Stopping fail2ban" - start-stop-daemon --stop --pidfile /var/run/fail2ban/fail2ban.pid --retry 30 \ + start-stop-daemon --stop --pidfile "${pidfile}" --retry 30 \ -- ${command} ${command_args} stop eend $? "Failed to stop fail2ban" } From 0b146208eb3a6f3ceb04d59e9e89c1cc914854ea Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 13:32:03 -0400 Subject: [PATCH 08/22] files/fail2ban-openrc.init: move pre-flight checks into start_pre(). Our OpenRC service script performs two tasks before starting the service: 1. It removes any stake sockets (from e.g. a system crash). 2. It ensures that the PID file directory exists. These have both been moved into the "start_pre" phase, which is designed to do such things (and will allow us to simplify the "start" phase in the future). The existing "mkdir -p" has also been converted into a "checkpath -d" command which is built-in to OpenRC. --- files/fail2ban-openrc.init | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/files/fail2ban-openrc.init b/files/fail2ban-openrc.init index 9969a3e0..e1cf5273 100755 --- a/files/fail2ban-openrc.init +++ b/files/fail2ban-openrc.init @@ -32,12 +32,16 @@ depend() { after iptables } +start_pre() { + checkpath -d "${pidfile%/*}" || return 1 + + # Remove stale socket after system crash, Gentoo bug 347477 + rm -f /var/run/fail2ban/fail2ban.sock || return 1 +} + start() { ebegin "Starting fail2ban" - mkdir -p /var/run/fail2ban || return 1 - # remove stalled sock file after system crash - # bug 347477 - rm -f /var/run/fail2ban/fail2ban.sock || return 1 + start-stop-daemon --start --pidfile "${pidfile}" \ -- ${command} ${command_args} start eend $? "Failed to start fail2ban" From e0097aefb95bac48c992f6b5ae58fc99140ecc03 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 13:37:00 -0400 Subject: [PATCH 09/22] files/fail2ban-openrc.init: use RC_SVCNAME instead of hard-coding the name. If our service is installed under some other name, then we don't want the service script to say things like "Starting fail2ban..." because the name "fail2ban" won't make any sense at that point. Instead, we use the $RC_SVCNAME variable to ensure that the service name matches what we tell the user. Typically, however, $RC_SVCNAME will still be "fail2ban". --- files/fail2ban-openrc.init | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/files/fail2ban-openrc.init b/files/fail2ban-openrc.init index e1cf5273..bcbdf8fd 100755 --- a/files/fail2ban-openrc.init +++ b/files/fail2ban-openrc.init @@ -40,24 +40,24 @@ start_pre() { } start() { - ebegin "Starting fail2ban" + ebegin "Starting ${RC_SVCNAME}" start-stop-daemon --start --pidfile "${pidfile}" \ -- ${command} ${command_args} start - eend $? "Failed to start fail2ban" + eend $? "Failed to start ${RC_SVCNAME}" } stop() { - ebegin "Stopping fail2ban" + ebegin "Stopping ${RC_SVCNAME}" start-stop-daemon --stop --pidfile "${pidfile}" --retry 30 \ -- ${command} ${command_args} stop - eend $? "Failed to stop fail2ban" + eend $? "Failed to stop ${RC_SVCNAME}" } reload() { - ebegin "Reloading fail2ban" + ebegin "Reloading ${RC_SVCNAME}" ${command} ${command_args} reload - eend $? "Failed to reload fail2ban" + eend $? "Failed to reload ${RC_SVCNAME}" } showlog(){ From c8ed0e0d913feeb361de800d1af6fd56e96bb840 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 13:44:53 -0400 Subject: [PATCH 10/22] files/fail2ban-openrc.init: use the standard OpenRC "retry" variable. If the "retry" variable is set in the service script, we don't have to pass it to start-stop-daemon explicitly. While we can't immediately eliminate any code with this change, it will be necessary later to adopt the default OpenRC stop() function. --- files/fail2ban-openrc.init | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/files/fail2ban-openrc.init b/files/fail2ban-openrc.init index bcbdf8fd..e3ddfe1a 100755 --- a/files/fail2ban-openrc.init +++ b/files/fail2ban-openrc.init @@ -26,6 +26,7 @@ extra_started_commands="reload showlog" command="/usr/bin/fail2ban-client" command_args="${FAIL2BAN_OPTIONS}" pidfile="/run/${RC_SVCNAME}/${RC_SVCNAME}.pid" +retry="30" depend() { use logger @@ -49,7 +50,7 @@ start() { stop() { ebegin "Stopping ${RC_SVCNAME}" - start-stop-daemon --stop --pidfile "${pidfile}" --retry 30 \ + start-stop-daemon --stop --pidfile "${pidfile}" --retry "${retry}" \ -- ${command} ${command_args} stop eend $? "Failed to stop ${RC_SVCNAME}" } From 80b1007a8fece5817f36ba19061d8359201669c5 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 13:54:22 -0400 Subject: [PATCH 11/22] files/fail2ban-openrc.init: remove the "showlog" command. The extra "showlog" command in our OpenRC service script was more trouble than it was worth: the only thing it did was call "less" on a log file, and the service script is only guessing at the location of the log file (only the fail2ban server knows its true location). It's not like "/etc/init.d/fail2ban showlog" is that much easier to type than "less /var/log/fail2ban.log" in the first place, so I think the extra complexity (5 more lines in the service script) is not worth it. --- files/fail2ban-openrc.init | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/files/fail2ban-openrc.init b/files/fail2ban-openrc.init index e3ddfe1a..2de5ae33 100755 --- a/files/fail2ban-openrc.init +++ b/files/fail2ban-openrc.init @@ -20,8 +20,7 @@ description="Daemon to ban hosts that cause multiple authentication errors" description_reload="reload configuration" -description_showlog="show fail2ban logs" -extra_started_commands="reload showlog" +extra_started_commands="reload" command="/usr/bin/fail2ban-client" command_args="${FAIL2BAN_OPTIONS}" @@ -60,7 +59,3 @@ reload() { ${command} ${command_args} reload eend $? "Failed to reload ${RC_SVCNAME}" } - -showlog(){ - less /var/log/fail2ban.log -} From 654fda8a50f65c6b329d75cbac91a50aa5a8a8f5 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 14:08:33 -0400 Subject: [PATCH 12/22] files/fail2ban-openrc*: let start-stop-daemon manage the server. There are two ways that it would make sense to write the OpenRC service script for fail2ban: 1. Use the fail2ban-client program to stop, start, reload, etc. the server; and try to figure out whether or not it worked afterwards. 2. Use the start-stop-daemon program built into OpenRC to manage the fail2ban-server process. This works only for starting and stopping, because the "reload" command is sent over an undocumented protocol, but has the benefit that you get immediate feedback about the result of calling fail2ban-server. The existing service script combined the two in a way that appeared to work, but didn't make too much sense. It used start-stop-daemon to initiate the fail2ban-client program with either a "start" or "stop" argument. So long as everything goes fine, that appears to work. But the start-stop-daemon is not actually monitoring the fail2ban-client program; it's supposed to be monitoring the fail2ban-server process that gets started as side-effect. The existing stop() function does not do quite what you'd expect; for example the "stop" command is never sent. Again, the daemon does ultimately get stopped so long as the hard-coded PID file contains what you think it does -- so it "works" -- but is misleading. This commit changes everything to use the second approach above, where start-stop-daemon manages everything. This was done mainly to simplify the service script, because now the default start() and stop() phases can be used, allowing us to delete them from our copy. One might worry that there is some special magic behind "fail2ban-client start" and "fail2ban-client stop", however that does not appear to be the case. Admittedly, if in the future those two commands begin to do something nonstandard, the service script would need to be changed again to take the first approach above and use fail2ban-client for everything. --- files/fail2ban-openrc.conf | 2 +- files/fail2ban-openrc.init | 31 +++++++++---------------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/files/fail2ban-openrc.conf b/files/fail2ban-openrc.conf index 1a2450e2..8493b03c 100644 --- a/files/fail2ban-openrc.conf +++ b/files/fail2ban-openrc.conf @@ -1,2 +1,2 @@ -# For available options, plase run "fail2ban-client -h". +# For available options, plase run "fail2ban-server --help". #FAIL2BAN_OPTIONS="" diff --git a/files/fail2ban-openrc.init b/files/fail2ban-openrc.init index 2de5ae33..21e251db 100755 --- a/files/fail2ban-openrc.init +++ b/files/fail2ban-openrc.init @@ -18,13 +18,15 @@ # Author: Sireyessire, Cyril Jaquier # -description="Daemon to ban hosts that cause multiple authentication errors" +description="Ban hosts that cause multiple authentication errors" description_reload="reload configuration" extra_started_commands="reload" -command="/usr/bin/fail2ban-client" -command_args="${FAIL2BAN_OPTIONS}" +# The fail2ban-client program is also capable of starting and stopping +# the server, but things are simpler if we let start-stop-daemon do it. +command="/usr/bin/fail2ban-server" pidfile="/run/${RC_SVCNAME}/${RC_SVCNAME}.pid" +command_args="${FAIL2BAN_OPTIONS} -p ${pidfile}" retry="30" depend() { @@ -34,28 +36,13 @@ depend() { start_pre() { checkpath -d "${pidfile%/*}" || return 1 - - # Remove stale socket after system crash, Gentoo bug 347477 - rm -f /var/run/fail2ban/fail2ban.sock || return 1 -} - -start() { - ebegin "Starting ${RC_SVCNAME}" - - start-stop-daemon --start --pidfile "${pidfile}" \ - -- ${command} ${command_args} start - eend $? "Failed to start ${RC_SVCNAME}" -} - -stop() { - ebegin "Stopping ${RC_SVCNAME}" - start-stop-daemon --stop --pidfile "${pidfile}" --retry "${retry}" \ - -- ${command} ${command_args} stop - eend $? "Failed to stop ${RC_SVCNAME}" } reload() { + # The fail2ban-client uses an undocumented protocol to tell + # the server to reload(), so we have to use it here rather + # than e.g. sending a signal to the server daemon. ebegin "Reloading ${RC_SVCNAME}" - ${command} ${command_args} reload + "${command%/*}/fail2ban-client" ${command_args} reload eend $? "Failed to reload ${RC_SVCNAME}" } From 4e7419e71f82481d321ac8c1b05ad0175d27e32d Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 14:12:20 -0400 Subject: [PATCH 13/22] files/fail2ban-openrc.conf: add back the "-x" example. I've removed the stale socket cleanup from our OpenRC service script: * Cleaning up stale sockets isn't really the job of the service script. * The ability to ignore a stale socket is already built into the server. With it gone, maybe the "-x" is a useful example to have in the conf file (although it's commented-out by default, anyway). --- files/fail2ban-openrc.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/fail2ban-openrc.conf b/files/fail2ban-openrc.conf index 8493b03c..9454ef68 100644 --- a/files/fail2ban-openrc.conf +++ b/files/fail2ban-openrc.conf @@ -1,2 +1,2 @@ # For available options, plase run "fail2ban-server --help". -#FAIL2BAN_OPTIONS="" +#FAIL2BAN_OPTIONS="-x" From e6a9f109c5349041987e64909917256e9c6e4229 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 14:22:35 -0400 Subject: [PATCH 14/22] files/fail2ban-openrc.init: force the socket location in the service script. The socket location needs to be set in the service script for the same reason that the PID file location does: because the service script is taking responsibility for ensuring that its parent directory exists and has the correct permissions. We can't do that if the end user is allowed to move the PID file or socket somewhere else (without parsing the config file, which has other security implications). --- files/fail2ban-openrc.init | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/files/fail2ban-openrc.init b/files/fail2ban-openrc.init index 21e251db..8473da26 100755 --- a/files/fail2ban-openrc.init +++ b/files/fail2ban-openrc.init @@ -22,11 +22,23 @@ description="Ban hosts that cause multiple authentication errors" description_reload="reload configuration" extra_started_commands="reload" +# Can't (and shouldn't) be changed by the end-user. +FAIL2BAN_RUNDIR="/run/${RC_SVCNAME}" +FAIL2BAN_SOCKET="${FAIL2BAN_RUNDIR}/${RC_SVCNAME}.sock" + +# This should be replaced by the build system, eventually. +FAIL2BAN_BINDIR="/usr/bin" + # The fail2ban-client program is also capable of starting and stopping # the server, but things are simpler if we let start-stop-daemon do it. -command="/usr/bin/fail2ban-server" -pidfile="/run/${RC_SVCNAME}/${RC_SVCNAME}.pid" -command_args="${FAIL2BAN_OPTIONS} -p ${pidfile}" +command="${FAIL2BAN_BINDIR}/fail2ban-server" +pidfile="${FAIL2BAN_RUNDIR}/${RC_SVCNAME}.pid" + +# We force the pidfile/socket location in this service script because +# we're taking responsibility for ensuring that their parent directory +# exists and has the correct permissions (which we can't do if the +# user is allowed to change them). +command_args="${FAIL2BAN_OPTIONS} -p ${pidfile} -s ${FAIL2BAN_SOCKET}" retry="30" depend() { @@ -35,7 +47,7 @@ depend() { } start_pre() { - checkpath -d "${pidfile%/*}" || return 1 + checkpath -d "${FAIL2BAN_RUNDIR}" || return 1 } reload() { @@ -43,6 +55,6 @@ reload() { # the server to reload(), so we have to use it here rather # than e.g. sending a signal to the server daemon. ebegin "Reloading ${RC_SVCNAME}" - "${command%/*}/fail2ban-client" ${command_args} reload + "${FAIL2BAN_BINDIR}/fail2ban-client" ${command_args} reload eend $? "Failed to reload ${RC_SVCNAME}" } From dd0f3487578e6feb54a54e774fcc40e390d769f8 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 14:32:07 -0400 Subject: [PATCH 15/22] files/fail2ban-openrc.init: replace @BINDIR@ at build-time. This commit renames fail2ban-openrc.init to fail2ban-openrc.init.in, and replaces the hard-coded value "/usr/bin" with "@BINDIR@" therein. At build-time, setup.py will replace that string with the correct value, and rename the file (without the ".in" suffix). This mimics the procedure done for "fail2ban-service.in" entirely. --- MANIFEST | 2 +- ...an-openrc.init => fail2ban-openrc.init.in} | 7 +--- setup.py | 39 ++++++++++--------- 3 files changed, 24 insertions(+), 24 deletions(-) rename files/{fail2ban-openrc.init => fail2ban-openrc.init.in} (91%) diff --git a/MANIFEST b/MANIFEST index ca9be123..5194e75b 100644 --- a/MANIFEST +++ b/MANIFEST @@ -376,7 +376,7 @@ files/fail2ban-tmpfiles.conf files/fail2ban.upstart files/gen_badbots files/fail2ban-openrc.conf -files/fail2ban-openrc.init +files/fail2ban-openrc.init.in files/ipmasq-ZZZzzz_fail2ban.rul files/logwatch/fail2ban files/logwatch/fail2ban-0.8.log diff --git a/files/fail2ban-openrc.init b/files/fail2ban-openrc.init.in similarity index 91% rename from files/fail2ban-openrc.init rename to files/fail2ban-openrc.init.in index 8473da26..f59a0a20 100755 --- a/files/fail2ban-openrc.init +++ b/files/fail2ban-openrc.init.in @@ -26,12 +26,9 @@ extra_started_commands="reload" FAIL2BAN_RUNDIR="/run/${RC_SVCNAME}" FAIL2BAN_SOCKET="${FAIL2BAN_RUNDIR}/${RC_SVCNAME}.sock" -# This should be replaced by the build system, eventually. -FAIL2BAN_BINDIR="/usr/bin" - # The fail2ban-client program is also capable of starting and stopping # the server, but things are simpler if we let start-stop-daemon do it. -command="${FAIL2BAN_BINDIR}/fail2ban-server" +command="@BINDIR@/fail2ban-server" pidfile="${FAIL2BAN_RUNDIR}/${RC_SVCNAME}.pid" # We force the pidfile/socket location in this service script because @@ -55,6 +52,6 @@ reload() { # the server to reload(), so we have to use it here rather # than e.g. sending a signal to the server daemon. ebegin "Reloading ${RC_SVCNAME}" - "${FAIL2BAN_BINDIR}/fail2ban-client" ${command_args} reload + "@BINDIR@/fail2ban-client" ${command_args} reload eend $? "Failed to reload ${RC_SVCNAME}" } diff --git a/setup.py b/setup.py index 8da29268..e18c99f3 100755 --- a/setup.py +++ b/setup.py @@ -95,24 +95,27 @@ class install_scripts_f2b(install_scripts): if install_dir.startswith(root): install_dir = install_dir[len(root):] except: # pragma: no cover - print('WARNING: Cannot find root-base option, check the bin-path to fail2ban-scripts in "fail2ban.service".') - print('Creating %s/fail2ban.service (from fail2ban.service.in): @BINDIR@ -> %s' % (buildroot, install_dir)) - with open(os.path.join(source_dir, 'files/fail2ban.service.in'), 'r') as fn: - lines = fn.readlines() - fn = None - if not dry_run: - fn = open(os.path.join(buildroot, 'fail2ban.service'), 'w') - try: - for ln in lines: - ln = re.sub(r'@BINDIR@', lambda v: install_dir, ln) - if dry_run: - sys.stdout.write(' | ' + ln) - continue - fn.write(ln) - finally: - if fn: fn.close() - if dry_run: - print(' `') + print('WARNING: Cannot find root-base option, check the bin-path to fail2ban-scripts in "fail2ban.service" and "fail2ban-openrc.init".') + + scripts = ['fail2ban.service', 'fail2ban-openrc.init'] + for script in scripts: + print('Creating %s/%s (from %s.in): @BINDIR@ -> %s' % (buildroot, script, script, install_dir)) + with open(os.path.join(source_dir, 'files/%s.in' % script), 'r') as fn: + lines = fn.readlines() + fn = None + if not dry_run: + fn = open(os.path.join(buildroot, script), 'w') + try: + for ln in lines: + ln = re.sub(r'@BINDIR@', lambda v: install_dir, ln) + if dry_run: + sys.stdout.write(' | ' + ln) + continue + fn.write(ln) + finally: + if fn: fn.close() + if dry_run: + print(' `') # Wrapper to specify fail2ban own options: From 36a7abe82fa17ed4cb697f745a48f77afd0618c8 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 16:28:20 -0400 Subject: [PATCH 16/22] files/fail2ban-openrc.init.in: mention that "reload" doesn't drop bans. The description of the "reload" OpenRC command just said that it would reload the configuration, which is true but not totally helpful. This commit updates it to mention that your existing bans won't be dropped, in contrast with the "restart" command that does drop your bans. --- files/fail2ban-openrc.init.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/fail2ban-openrc.init.in b/files/fail2ban-openrc.init.in index f59a0a20..a2f4d34f 100755 --- a/files/fail2ban-openrc.init.in +++ b/files/fail2ban-openrc.init.in @@ -19,7 +19,7 @@ # description="Ban hosts that cause multiple authentication errors" -description_reload="reload configuration" +description_reload="reload configuration without dropping bans" extra_started_commands="reload" # Can't (and shouldn't) be changed by the end-user. From 87e9cff065c9add436e4a9488239a89835b1bc48 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 16:49:49 -0400 Subject: [PATCH 17/22] files/fail2ban-openrc.init.in: remove redundant "return" from start_pre. OpenRC functions will exit with the return code from the last command by default, so there's no need for the "|| return 1" in our single-line start_pre() phase. --- files/fail2ban-openrc.init.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/fail2ban-openrc.init.in b/files/fail2ban-openrc.init.in index a2f4d34f..ad977274 100755 --- a/files/fail2ban-openrc.init.in +++ b/files/fail2ban-openrc.init.in @@ -44,7 +44,7 @@ depend() { } start_pre() { - checkpath -d "${FAIL2BAN_RUNDIR}" || return 1 + checkpath -d "${FAIL2BAN_RUNDIR}" } reload() { From 4d2841832cc3b38175bd0f0c3e6b8e143b5a0426 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 17:02:25 -0400 Subject: [PATCH 18/22] files/fail2ban-openrc.init.in: don't restart() with a broken config. This commit adds a new function checkconfig() to the OpenRC service script. All it does is run the server with the "--test" flag in addition to the usual command-line arguments. The new command is not user-facing, but lets us avoid restarting the daemon with a broken config. That helps when the user changes his configuration while the daemon is running, and then tries to restart() not knowing that the new config is broken. A priori, we would stop the daemon and then the error would only become visible when the subsequent start() command failed. Refusing to stop() with a broken configuration is a nicer thing to do. --- files/fail2ban-openrc.init.in | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/files/fail2ban-openrc.init.in b/files/fail2ban-openrc.init.in index ad977274..20465254 100755 --- a/files/fail2ban-openrc.init.in +++ b/files/fail2ban-openrc.init.in @@ -43,14 +43,39 @@ depend() { after iptables } +checkconfig() { + "${command}" ${command_args} --test +} + start_pre() { + # If this isn't a restart, make sure that the user's config isn't + # busted before we try to start the daemon (this will produce + # better error messages than if we just try to start it blindly). + # + # If, on the other hand, this *is* a restart, then the stop_pre + # action will have ensured that the config is usable and we don't + # need to do that again. + if [ "${RC_CMD}" != "restart" ] ; then + checkconfig || return $? + fi checkpath -d "${FAIL2BAN_RUNDIR}" } +stop_pre() { + # If this is a restart, check to make sure the user's config + # isn't busted before we stop the running daemon. + if [ "${RC_CMD}" = "restart" ] ; then + checkconfig || return $? + fi +} + reload() { # The fail2ban-client uses an undocumented protocol to tell # the server to reload(), so we have to use it here rather - # than e.g. sending a signal to the server daemon. + # than e.g. sending a signal to the server daemon. Note that + # the reload will fail (on the server side) if the new config + # is invalid; we therefore don't need to test it ourselves + # with checkconfig() before initiating the reload. ebegin "Reloading ${RC_SVCNAME}" "@BINDIR@/fail2ban-client" ${command_args} reload eend $? "Failed to reload ${RC_SVCNAME}" From 78dddb75e6f3f8f433a6f08add13bffbad90fc7c Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 15 Jul 2018 18:28:37 -0400 Subject: [PATCH 19/22] files/fail2ban-openrc.init.in: add a comment about @RUNDIR@ in the future. --- files/fail2ban-openrc.init.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/files/fail2ban-openrc.init.in b/files/fail2ban-openrc.init.in index 20465254..2c56ee3a 100755 --- a/files/fail2ban-openrc.init.in +++ b/files/fail2ban-openrc.init.in @@ -23,6 +23,10 @@ description_reload="reload configuration without dropping bans" extra_started_commands="reload" # Can't (and shouldn't) be changed by the end-user. +# +# Note that @BINDIR@ is already supplied by the build system. Some +# day, it might be nice to have @RUNDIR@ supplied by the build system +# as well, so that we don't have to hard-code /run here. FAIL2BAN_RUNDIR="/run/${RC_SVCNAME}" FAIL2BAN_SOCKET="${FAIL2BAN_RUNDIR}/${RC_SVCNAME}.sock" From 8f83242c25a957d34478e9604600066695be7998 Mon Sep 17 00:00:00 2001 From: "Sergey G. Brester" Date: Mon, 20 Dec 2021 15:39:57 +0100 Subject: [PATCH 20/22] suppress unneeded info (moved to debug level) see #3186 --- fail2ban/server/server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fail2ban/server/server.py b/fail2ban/server/server.py index bd2c7ad3..627ffe8d 100644 --- a/fail2ban/server/server.py +++ b/fail2ban/server/server.py @@ -372,7 +372,7 @@ class Server: if isinstance(filter_, FileFilter): return filter_.getLogPaths() else: # pragma: systemd no cover - logSys.info("Jail %s is not a FileFilter instance" % name) + logSys.debug("Jail %s is not a FileFilter instance" % name) return [] def addJournalMatch(self, name, match): # pragma: systemd no cover @@ -390,7 +390,7 @@ class Server: if isinstance(filter_, JournalFilter): return filter_.getJournalMatch() else: - logSys.info("Jail %s is not a JournalFilter instance" % name) + logSys.debug("Jail %s is not a JournalFilter instance" % name) return [] def setLogEncoding(self, name, encoding): From 8bf15db688ac0f95f6f1489947ee00825340b23e Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 18 Jan 2022 15:06:16 +0100 Subject: [PATCH 21/22] filter.d/sshd.conf: `ddos` mode extended - recognizes new message "banner exchange: invalid format" generated by port scanner, https payload on ssh port; closes gh-3169 --- config/filter.d/sshd.conf | 1 + fail2ban/tests/files/logs/sshd | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/config/filter.d/sshd.conf b/config/filter.d/sshd.conf index e7942262..c265b9eb 100644 --- a/config/filter.d/sshd.conf +++ b/config/filter.d/sshd.conf @@ -75,6 +75,7 @@ mdre-ddos = ^Did not receive identification string from ^Bad protocol version identification '.*' from ^SSH: Server;Ltype: (?:Authname|Version|Kex);Remote: -\d+;[A-Z]\w+: ^Read from socket failed: Connection reset by peer + ^banner exchange: Connection from <__on_port_opt>: invalid format # same as mdre-normal-other, but as failure (without ) and [preauth] only: mdre-ddos-other = ^(Connection (?:closed|reset)|Disconnected) (?:by|from)%(__authng_user)s %(__on_port_opt)s\s+\[preauth\]\s*$ diff --git a/fail2ban/tests/files/logs/sshd b/fail2ban/tests/files/logs/sshd index 5d23f96f..ac8524a8 100644 --- a/fail2ban/tests/files/logs/sshd +++ b/fail2ban/tests/files/logs/sshd @@ -315,6 +315,11 @@ Feb 17 17:40:17 sshd[19725]: error: kex_exchange_identification: client sent inv # failJSON: { "time": "2005-02-17T17:40:18", "match": true , "host": "192.0.2.10", "desc": "ddos: flood attack vector, gh-2850" } Feb 17 17:40:18 sshd[19725]: error: kex_exchange_identification: Connection closed by remote host +# failJSON: { "match": false } +Mar 1 18:59:33 hostname sshd[1189575]: error: kex_exchange_identification: banner line too long +# failJSON: { "time": "2005-03-01T18:59:33", "match": true , "host": "192.0.2.12", "desc": "ddos: port scanner, https payload on ssh port (banner exchange: invalid format, gh-3169)" } +Mar 1 18:59:33 hostname sshd[1189575]: banner exchange: Connection from 192.0.2.12 port 44105: invalid format + # failJSON: { "time": "2005-03-15T09:21:01", "match": true , "host": "192.0.2.212", "desc": "DDOS mode causes failure on close within preauth stage" } Mar 15 09:21:01 host sshd[2717]: Connection closed by 192.0.2.212 [preauth] # failJSON: { "time": "2005-03-15T09:21:02", "match": true , "host": "192.0.2.212", "desc": "DDOS mode causes failure on close within preauth stage" } From bf689c27b833d4cafc6ce34ada214cd4df2d7d86 Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 18 Jan 2022 15:30:27 +0100 Subject: [PATCH 22/22] filter.d/sshd.conf: `ddos` mode extended - recognizes messages "kex_exchange_identification: Connection closed / reset by pear" (fixed possible regression of f77398c49d4eeb529a1684a27dcfbf5b6aaafa66); closes gh-3086 --- config/filter.d/sshd.conf | 7 ++++--- fail2ban/tests/files/logs/sshd | 12 ++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/config/filter.d/sshd.conf b/config/filter.d/sshd.conf index c265b9eb..d5d189b0 100644 --- a/config/filter.d/sshd.conf +++ b/config/filter.d/sshd.conf @@ -68,16 +68,17 @@ cmnfailed = > mdre-normal = # used to differentiate "connection closed" with and without `[preauth]` (fail/nofail cases in ddos mode) -mdre-normal-other = ^(Connection closed|Disconnected) (?:by|from)%(__authng_user)s (?:%(__suff)s|\s*)$ +mdre-normal-other = ^(Connection (?:closed|reset)|Disconnected) (?:by|from)%(__authng_user)s (?:%(__suff)s|\s*)$ mdre-ddos = ^Did not receive identification string from - ^kex_exchange_identification: (?:[Cc]lient sent invalid protocol identifier|[Cc]onnection closed by remote host) + ^kex_exchange_identification: (?:read: )?(?:[Cc]lient sent invalid protocol identifier|[Cc]onnection (?:closed by remote host|reset by peer)) ^Bad protocol version identification '.*' from ^SSH: Server;Ltype: (?:Authname|Version|Kex);Remote: -\d+;[A-Z]\w+: ^Read from socket failed: Connection reset by peer ^banner exchange: Connection from <__on_port_opt>: invalid format -# same as mdre-normal-other, but as failure (without ) and [preauth] only: +# same as mdre-normal-other, but as failure (without with [preauth] and with on no preauth phase as helper to identify address): mdre-ddos-other = ^(Connection (?:closed|reset)|Disconnected) (?:by|from)%(__authng_user)s %(__on_port_opt)s\s+\[preauth\]\s*$ + ^(Connection (?:closed|reset)|Disconnected) (?:by|from)%(__authng_user)s (?:%(__on_port_opt)s|\s*)$ mdre-extra = ^Received disconnect from %(__on_port_opt)s:\s*14: No(?: supported)? authentication methods available ^Unable to negotiate with %(__on_port_opt)s: no matching <__alg_match> found. diff --git a/fail2ban/tests/files/logs/sshd b/fail2ban/tests/files/logs/sshd index ac8524a8..99c3756b 100644 --- a/fail2ban/tests/files/logs/sshd +++ b/fail2ban/tests/files/logs/sshd @@ -333,6 +333,18 @@ Jun 6 04:17:04 host sshd[1189074]: Invalid user from 192.0.2.68 port 34916 # failJSON: { "time": "2005-06-06T04:17:09", "match": true , "host": "192.0.2.68", "dns": null, "user": "", "desc": "empty user, gh-2749" } Jun 6 04:17:09 host sshd[1189074]: Connection closed by invalid user 192.0.2.68 port 34916 [preauth] +# failJSON: { "match": false, "desc": "ddos-failure without IP, retarded, must be triggered with next (closed) message, gh-3086"} +Jun 7 04:10:35 host sshd[424228]: error: kex_exchange_identification: Connection closed by remote host +# failJSON: { "time": "2005-06-07T04:10:35", "match": true , "host": "192.0.2.15", "desc": "kex_exchange_identification: Connection closed, gh-3086" } +Jun 7 04:10:35 host sshd[424228]: Connection closed by 192.0.2.15 port 35352 + +# failJSON: { "match": false } +Jun 7 04:29:10 host sshd[649921]: Connection from 192.0.2.16 port 51280 on 192.0.2.16 port 22 rdomain "" +# failJSON: { "time": "2005-06-07T04:29:10", "match": true, "host": "192.0.2.16", "desc": "ddos-failure without IP, must be triggered here because it became known above, gh-3086"} +Jun 7 04:29:10 host sshd[649921]: error: kex_exchange_identification: read: Connection reset by peer +# failJSON: { "match": false, "desc": "Connection reset already triggered above (known IP, no-fail helper unused here)" } +Jun 7 04:29:10 host sshd[649921]: Connection reset by 192.0.2.16 port 51280 + # filterOptions: [{"mode": "extra"}, {"mode": "aggressive"}] # several other cases from gh-864: