fail2ban: bump to 1.1.0
authorAndrey Zotikov <[email protected]>
Wed, 23 Jul 2025 22:58:31 +0000 (01:58 +0300)
committerWesley Gimenes <[email protected]>
Sun, 28 Sep 2025 17:29:07 +0000 (14:29 -0300)
fail2ban changes:
- nftables support (iptables dependency removed)
- python3 support (old package patches removed)
- Upstream patches backports:
  - filter.d/dropbear.conf: failregex extended to match different format of "Exit before auth" message
  - cherry-pick from debian: debian default banactions are nftables, systemd backend for sshd
- Removed unresponsive/unreachable maintainer.

Fixes: https://github.com/openwrt/packages/issues/23015 ("fail2ban: very old version")
Signed-off-by: Andrey Zotikov <[email protected]>
net/fail2ban/Makefile
net/fail2ban/patches/010-dropbear-regex-fix.patch [new file with mode: 0644]
net/fail2ban/patches/010-python3.10_compat.patch [deleted file]
net/fail2ban/patches/020-fix-2to3.patch [deleted file]
net/fail2ban/patches/020-nftables.patch [new file with mode: 0644]
net/fail2ban/patches/101-move-global-groups-to-start-of-expression-python-3.11-compat.patch [deleted file]
net/fail2ban/patches/102-wrap-global-flags-to-local-flags-if-supported-by-RE-engine-in-the-python-version.patch [deleted file]
net/fail2ban/patches/CVE-2021-32749.patch [deleted file]

index a4b25f2a217a6052a6680ba74197d97160b1b342..a963af1f621cc3e2f418168b2afca035e371e168 100644 (file)
@@ -6,14 +6,14 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=fail2ban
-PKG_VERSION:=0.11.2
-PKG_RELEASE:=9
+PKG_VERSION:=1.1.0
+PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/fail2ban/fail2ban/tar.gz/$(PKG_VERSION)?
-PKG_HASH:=383108e5f8644cefb288537950923b7520f642e7e114efb843f6e7ea9268b1e0
+PKG_HASH:=474fcc25afdaf929c74329d1e4d24420caabeea1ef2e041a267ce19269570bae
 
-PKG_MAINTAINER:=Gerald Kerma <[email protected]>
+PKG_MAINTAINER:=
 PKG_LICENSE:=GPL-2.0-or-later
 PKG_LICENSE_FILES:=COPYING
 PKG_CPE_ID:=cpe:/a:fail2ban:fail2ban
@@ -21,15 +21,13 @@ PKG_CPE_ID:=cpe:/a:fail2ban:fail2ban
 include $(INCLUDE_DIR)/package.mk
 include ../../lang/python/python3-package.mk
 
-HOST_BUILD_DEPENDS:=2to3/host
-
 define Package/fail2ban
   SECTION:=net
   CATEGORY:=Network
   TITLE:=ban hosts that cause multiple authentication errors
   URL:=https://www.fail2ban.org/
   DEPENDS:= \
-  +iptables \
+  +nftables \
   +python3-light \
   +python3-ctypes \
   +python3-distutils \
@@ -50,7 +48,6 @@ define Package/fail2ban/conffiles
 endef
 
 define Build/Compile
-       cd $(PKG_BUILD_DIR) && ./fail2ban-2to3
        $(call Py3Build/Compile)
 endef
 
diff --git a/net/fail2ban/patches/010-dropbear-regex-fix.patch b/net/fail2ban/patches/010-dropbear-regex-fix.patch
new file mode 100644 (file)
index 0000000..351cf97
--- /dev/null
@@ -0,0 +1,44 @@
+From f29a49e39c66e43de6cf1d2a9085c00cca5eca99 Mon Sep 17 00:00:00 2001
+From: sebres <[email protected]>
+Date: Fri, 27 Dec 2024 16:43:33 +0100
+Subject: [PATCH] `filter.d/dropbear.conf`: failregex extended to match
+ different format of "Exit before auth" message; closes gh-3791
+
+Upstream-Status: Backport [https://github.com/fail2ban/fail2ban/commit/a796cc9b91656721fee0d1904911101c678452ad]
+
+Signed-off-by: Andrey Zotikov <[email protected]>
+---
+ config/filter.d/dropbear.conf      | 7 ++++---
+ fail2ban/tests/files/logs/dropbear | 8 ++++++++
+ 2 files changed, 12 insertions(+), 3 deletions(-)
+
+--- a/config/filter.d/dropbear.conf
++++ b/config/filter.d/dropbear.conf
+@@ -25,9 +25,10 @@ _daemon = dropbear
+ prefregex = ^%(__prefix_line)s<F-CONTENT>(?:[Ll]ogin|[Bb]ad|[Ee]xit).+</F-CONTENT>$
+-failregex = ^[Ll]ogin attempt for nonexistent user ('.*' )?from <HOST>:\d+$
+-            ^[Bb]ad (PAM )?password attempt for .+ from <HOST>(:\d+)?$
+-            ^[Ee]xit before auth \(user '.+', \d+ fails\): Max auth tries reached - user '.+' from <HOST>:\d+\s*$
++failregex = ^[Ll]ogin attempt for nonexistent user (?:'<F-USER>.*</F-USER>' )?from <HOST>:\d+$
++            ^[Bb]ad (?:PAM )?password attempt for '<F-USER>.+</F-USER>' from <HOST>(?::\d+)?$
++            ^[Ee]xit before auth from \<?<ADDR>:\d+\>?: (?:\([^\)]*\): )?Max auth tries reached - user '<F-USER>.+</F-USER>'\s*$
++            ^[Ee]xit before auth \(user '.+', \d+ fails\): Max auth tries reached - user '<F-USER>.+</F-USER>' from <HOST>:\d+\s*$
+ ignoreregex = 
+--- a/fail2ban/tests/files/logs/dropbear
++++ b/fail2ban/tests/files/logs/dropbear
+@@ -13,3 +13,11 @@ Jul 27 01:04:12 fail2ban-test dropbear[1
+ Jul 27 01:04:22 fail2ban-test dropbear[1335]: Exit before auth (user 'root', 10 fails): Max auth tries reached - user 'root' from 1.2.3.4:60588
+ # failJSON: { "time": "2005-07-27T01:18:59", "match": true , "host": "1.2.3.4" }
+ Jul 27 01:18:59 fail2ban-test dropbear[1477]: Login attempt for nonexistent user from 1.2.3.4:60794
++
++# failJSON: { "time": "2005-07-10T23:53:52", "match": true , "host": "1.2.3.4", "desc": "extra pid/timestamp may be logged into journal, gh-3597" }
++Jul 10 23:53:52 fail2ban-test dropbear[825]: [825] Jul 10 23:53:52 Bad password attempt for 'root' from 1.2.3.4:52289
++
++# failJSON: { "time": "2005-07-10T23:57:29", "match": true , "host": "192.0.2.3", "desc": "different message format, gh-3791" }
++Jul 10 23:57:29 fail2ban-test dropbear[825]: [825] Jul 10 23:57:29 Exit before auth from <192.0.2.3:52289>: (user 'root', 10 fails): Max auth tries reached - user 'root'
++# failJSON: { "time": "2005-07-10T23:59:24", "match": true , "host": "192.0.2.3", "desc": "different message format, gh-3791" }
++Jul 10 23:59:24 fail2ban-test dropbear[826]: [826] Jul 10 23:59:24 Exit before auth from <192.0.2.3:52325>: Max auth tries reached - user 'is invalid'
diff --git a/net/fail2ban/patches/010-python3.10_compat.patch b/net/fail2ban/patches/010-python3.10_compat.patch
deleted file mode 100644 (file)
index 24aec98..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-From 2b6bb2c1bed8f7009631e8f8c306fa3160324a49 Mon Sep 17 00:00:00 2001
-From: "Sergey G. Brester" <[email protected]>
-Date: Mon, 8 Feb 2021 17:19:24 +0100
-Subject: [PATCH 2/4] follow bpo-37324:
- :ref:`collections-abstract-base-classes` moved to the :mod:`collections.abc`
- module
-
-(since 3.10-alpha.5 `MutableMapping` is missing in collections module)
----
- fail2ban/server/action.py | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
---- a/fail2ban/server/action.py
-+++ b/fail2ban/server/action.py
-@@ -30,7 +30,10 @@ import tempfile
- import threading
- import time
- from abc import ABCMeta
--from collections import MutableMapping
-+try:
-+      from collections.abc import MutableMapping
-+except ImportError:
-+      from collections import MutableMapping
- from .failregex import mapTag2Opt
- from .ipdns import DNSUtils
---- a/fail2ban/server/actions.py
-+++ b/fail2ban/server/actions.py
-@@ -28,7 +28,10 @@ import logging
- import os
- import sys
- import time
--from collections import Mapping
-+try:
-+      from collections.abc import Mapping
-+except ImportError:
-+      from collections import Mapping
- try:
-       from collections import OrderedDict
- except ImportError:
---- a/fail2ban/server/jails.py
-+++ b/fail2ban/server/jails.py
-@@ -22,7 +22,10 @@ __copyright__ = "Copyright (c) 2004 Cyri
- __license__ = "GPL"
- from threading import Lock
--from collections import Mapping
-+try:
-+      from collections.abc import Mapping
-+except ImportError:
-+      from collections import Mapping
- from ..exceptions import DuplicateJailException, UnknownJailException
- from .jail import Jail
diff --git a/net/fail2ban/patches/020-fix-2to3.patch b/net/fail2ban/patches/020-fix-2to3.patch
deleted file mode 100644 (file)
index 203e2c7..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-From 196c55e93103d1e56d1336f27a5f2591b4e54fef Mon Sep 17 00:00:00 2001
-From: sebres <[email protected]>
-Date: Sun, 19 Sep 2021 18:49:18 +0200
-Subject: [PATCH] fix gh-3098: build fails with error in fail2ban setup
- command: use_2to3 is invalid (setuptools 58+)
-
----
- setup.py | 16 +---------------
- 1 file changed, 1 insertion(+), 15 deletions(-)
-
---- a/setup.py
-+++ b/setup.py
-@@ -56,7 +56,7 @@ import warnings
- from glob import glob
- from fail2ban.setup import updatePyExec
--
-+from fail2ban.version import version
- source_dir = os.path.realpath(os.path.dirname(
-       # __file__ seems to be overwritten sometimes on some python versions (e.g. bug of 2.6 by running under cProfile, etc.):
-@@ -120,22 +120,12 @@ class install_scripts_f2b(install_script
- # Wrapper to specify fail2ban own options:
- class install_command_f2b(install):
-       user_options = install.user_options + [
--              ('disable-2to3', None, 'Specify to deactivate 2to3, e.g. if the install runs from fail2ban test-cases.'),
-               ('without-tests', None, 'without tests files installation'),
-       ]
-       def initialize_options(self):
--              self.disable_2to3 = None
-               self.without_tests = not with_tests
-               install.initialize_options(self)
-       def finalize_options(self):
--              global _2to3
--              ## in the test cases 2to3 should be already done (fail2ban-2to3):
--              if self.disable_2to3:
--                      _2to3 = False
--              if _2to3:
--                      cmdclass = self.distribution.cmdclass
--                      cmdclass['build_py'] = build_py_2to3
--                      cmdclass['build_scripts'] = build_scripts_2to3
-               if self.without_tests:
-                       self.distribution.scripts.remove('bin/fail2ban-testcases')
-@@ -186,7 +176,6 @@ commands.'''
- if setuptools:
-       setup_extra = {
-               'test_suite': "fail2ban.tests.utils.gatherTests",
--              'use_2to3': True,
-       }
- else:
-       setup_extra = {}
-@@ -210,9 +199,6 @@ if platform_system in ('linux', 'solaris
-               ('/usr/share/doc/fail2ban', doc_files)
-       )
--# Get version number, avoiding importing fail2ban.
--# This is due to tests not functioning for python3 as 2to3 takes place later
--exec(open(join("fail2ban", "version.py")).read())
- setup(
-       name = "fail2ban",
diff --git a/net/fail2ban/patches/020-nftables.patch b/net/fail2ban/patches/020-nftables.patch
new file mode 100644 (file)
index 0000000..bc2f2e4
--- /dev/null
@@ -0,0 +1,41 @@
+From d56cda8f2a8dc3f69943545255d6934a73d0b1aa Mon Sep 17 00:00:00 2001
+From: sebres <[email protected]>
+Date: Fri, 26 Apr 2024 00:25:19 +0200
+Subject: [PATCH] cherry-pick from debian: debian default banactions are
+ nftables, systemd backend for sshd closes gh-3292
+
+Upstream-Status: Backport [https://github.com/fail2ban/fail2ban/commit/d0d07285234871bad3dc0c359d0ec03365b6dddc]
+
+Signed-off-by: Andrey Zotikov <[email protected]>
+---
+ config/jail.conf         | 4 ++--
+ config/paths-debian.conf | 5 +++++
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+
+--- a/config/jail.conf
++++ b/config/jail.conf
+@@ -205,8 +205,8 @@ fail2ban_agent = Fail2Ban/%(fail2ban_ver
+ # iptables-multiport, shorewall, etc) It is used to define
+ # action_* variables. Can be overridden globally or per
+ # section within jail.local file
+-banaction = iptables-multiport
+-banaction_allports = iptables-allports
++#banaction = iptables-multiport
++#banaction_allports = iptables-allports
+ # The simplest action to take: ban only
+ action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
+--- a/config/paths-debian.conf
++++ b/config/paths-debian.conf
+@@ -9,6 +9,11 @@ after  = paths-overrides.local
+ [DEFAULT]
++banaction = nftables
++banaction_allports = nftables[type=allports]
++
++sshd_backend = systemd
++
+ syslog_mail = /var/log/mail.log
+ # control the `mail.warn` setting, see `/etc/rsyslog.d/50-default.conf` (if commented `mail.*` wins).
diff --git a/net/fail2ban/patches/101-move-global-groups-to-start-of-expression-python-3.11-compat.patch b/net/fail2ban/patches/101-move-global-groups-to-start-of-expression-python-3.11-compat.patch
deleted file mode 100644 (file)
index bd50c17..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-From 7e2ab36d86998575853150c0a57de5e22518cf66 Mon Sep 17 00:00:00 2001
-From: sebres <[email protected]>
-Date: Tue, 21 Jun 2022 16:55:57 +0200
-Subject: [PATCH] move global groups to start of expression (python 3.11
- compat)
-
-[remove change to regex not in 0.11.2]
-Signed-off-by: Jeffery To <[email protected]>
----
- fail2ban/client/fail2banregex.py | 2 +-
- fail2ban/server/datetemplate.py  | 8 ++++++++
- 2 files changed, 9 insertions(+), 1 deletion(-)
-
---- a/fail2ban/server/datetemplate.py
-+++ b/fail2ban/server/datetemplate.py
-@@ -35,6 +35,7 @@ logSys = getLogger(__name__)
- # check already grouped contains "(", but ignores char "\(" and conditional "(?(id)...)":
- RE_GROUPED = re.compile(r'(?<!(?:\(\?))(?<!\\)\((?!\?)')
- RE_GROUP = ( re.compile(r'^((?:\(\?\w+\))?\^?(?:\(\?\w+\))?)(.*?)(\$?)$'), r"\1(\2)\3" )
-+RE_GLOBALFLAGS = re.compile(r'((?:^|(?!<\\))\(\?[a-z]+\))')
- RE_EXLINE_NO_BOUNDS = re.compile(r'^\{UNB\}')
- RE_EXLINE_BOUND_BEG = re.compile(r'^\{\^LN-BEG\}')
-@@ -110,6 +111,11 @@ class DateTemplate(object):
-               # because it may be very slow in negative case (by long log-lines not matching pattern)
-               regex = regex.strip()
-+              # cut global flags like (?iu) from RE in order to pre-set it after processing:
-+              gf = RE_GLOBALFLAGS.search(regex)
-+              if gf:
-+                      regex = RE_GLOBALFLAGS.sub('', regex, count=1)
-+              # check word boundaries needed:
-               boundBegin = wordBegin and not RE_NO_WRD_BOUND_BEG.search(regex)
-               boundEnd = wordEnd and not RE_NO_WRD_BOUND_END.search(regex)
-               # if no group add it now, should always have a group(1):
-@@ -135,6 +141,8 @@ class DateTemplate(object):
-                       self.flags |= DateTemplate.LINE_END
-               # remove possible special pattern "**" in front and end of regex:
-               regex = RE_DEL_WRD_BOUNDS[0].sub(RE_DEL_WRD_BOUNDS[1], regex)
-+              if gf: # restore global flags:
-+                      regex = gf.group(1) + regex
-               self._regex = regex
-               logSys.log(7, '  constructed regex %s', regex)
-               self._cRegex = None
diff --git a/net/fail2ban/patches/102-wrap-global-flags-to-local-flags-if-supported-by-RE-engine-in-the-python-version.patch b/net/fail2ban/patches/102-wrap-global-flags-to-local-flags-if-supported-by-RE-engine-in-the-python-version.patch
deleted file mode 100644 (file)
index 5a677c1..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-From 4337e366163278815ea9fc6c952bffb579e885a0 Mon Sep 17 00:00:00 2001
-From: sebres <[email protected]>
-Date: Tue, 21 Jun 2022 16:56:57 +0200
-Subject: [PATCH] wrap global flags like ((?i)xxx) or (?:(?i)xxx) to local
- flags (?i:xxx) if supported by RE-engine in the python version
-
----
- fail2ban/server/failregex.py | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/fail2ban/server/failregex.py
-+++ b/fail2ban/server/failregex.py
-@@ -91,6 +91,13 @@ R_MAP = {
-       "port": "fport",
- }
-+# map global flags like ((?i)xxx) or (?:(?i)xxx) to local flags (?i:xxx) if supported by RE-engine in this python version:
-+try:
-+      re.search("^re(?i:val)$", "reVAL")
-+      R_GLOB2LOCFLAGS = ( re.compile(r"(?<!\\)\((?:\?:)?(\(\?[a-z]+)\)"), r"\1:" )
-+except:
-+      R_GLOB2LOCFLAGS = ()
-+
- def mapTag2Opt(tag):
-       tag = tag.lower()
-       return R_MAP.get(tag, tag)
-@@ -128,6 +135,9 @@ class Regex:
-               #
-               if regex.lstrip() == '':
-                       raise RegexException("Cannot add empty regex")
-+              # special handling wrapping global flags to local flags:
-+              if R_GLOB2LOCFLAGS:
-+                      regex = R_GLOB2LOCFLAGS[0].sub(R_GLOB2LOCFLAGS[1], regex)
-               try:
-                       self._regexObj = re.compile(regex, re.MULTILINE if multiline else 0)
-                       self._regex = regex
diff --git a/net/fail2ban/patches/CVE-2021-32749.patch b/net/fail2ban/patches/CVE-2021-32749.patch
deleted file mode 100644 (file)
index d84f2ed..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-From 410a6ce5c80dd981c22752da034f2529b5eee844 Mon Sep 17 00:00:00 2001
-From: sebres <[email protected]>
-Date: Mon, 21 Jun 2021 17:12:53 +0200
-Subject: [PATCH] fixed possible RCE vulnerability, unset escape variable
- (default tilde) stops consider "~" char after new-line as composing escape
- sequence
-
----
- config/action.d/complain.conf         | 2 +-
- config/action.d/dshield.conf          | 2 +-
- config/action.d/mail-buffered.conf    | 8 ++++----
- config/action.d/mail-whois-lines.conf | 2 +-
- config/action.d/mail-whois.conf       | 6 +++---
- config/action.d/mail.conf             | 6 +++---
- 6 files changed, 13 insertions(+), 13 deletions(-)
-
---- a/config/action.d/complain.conf
-+++ b/config/action.d/complain.conf
-@@ -102,7 +102,7 @@ logpath = /dev/null
- # Notes.:  Your system mail command. Is passed 2 args: subject and recipient
- # Values:  CMD
- #
--mailcmd = mail -s
-+mailcmd = mail -E 'set escape' -s
- # Option:  mailargs
- # Notes.:  Additional arguments to mail command. e.g. for standard Unix mail:
---- a/config/action.d/dshield.conf
-+++ b/config/action.d/dshield.conf
-@@ -179,7 +179,7 @@ tcpflags =
- # Notes.:  Your system mail command. Is passed 2 args: subject and recipient
- # Values:  CMD
- #
--mailcmd = mail -s
-+mailcmd = mail -E 'set escape' -s
- # Option:  mailargs
- # Notes.:  Additional arguments to mail command. e.g. for standard Unix mail:
---- a/config/action.d/mail-buffered.conf
-+++ b/config/action.d/mail-buffered.conf
-@@ -17,7 +17,7 @@ actionstart = printf %%b "Hi,\n
-               The jail <name> has been started successfully.\n
-               Output will be buffered until <lines> lines are available.\n
-               Regards,\n
--              Fail2Ban"|mail -s "[Fail2Ban] <name>: started on <fq-hostname>" <dest>
-+              Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: started on <fq-hostname>" <dest>
- # Option:  actionstop
- # Notes.:  command executed at the stop of jail (or at the end of Fail2Ban)
-@@ -28,13 +28,13 @@ actionstop = if [ -f <tmpfile> ]; then
-                  These hosts have been banned by Fail2Ban.\n
-                  `cat <tmpfile>`
-                  Regards,\n
--                 Fail2Ban"|mail -s "[Fail2Ban] <name>: Summary from <fq-hostname>" <dest>
-+                 Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: Summary from <fq-hostname>" <dest>
-                  rm <tmpfile>
-              fi
-              printf %%b "Hi,\n
-              The jail <name> has been stopped.\n
-              Regards,\n
--             Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped on <fq-hostname>" <dest>
-+             Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: stopped on <fq-hostname>" <dest>
- # Option:  actioncheck
- # Notes.:  command executed once before each actionban command
-@@ -55,7 +55,7 @@ actionban = printf %%b "`date`: <ip> (<f
-                 These hosts have been banned by Fail2Ban.\n
-                 `cat <tmpfile>`
-                 \nRegards,\n
--                Fail2Ban"|mail -s "[Fail2Ban] <name>: Summary" <dest>
-+                Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: Summary" <dest>
-                 rm <tmpfile>
-             fi
---- a/config/action.d/mail-whois-lines.conf
-+++ b/config/action.d/mail-whois-lines.conf
-@@ -72,7 +72,7 @@ actionunban =
- # Notes.:  Your system mail command. Is passed 2 args: subject and recipient
- # Values:  CMD
- #
--mailcmd = mail -s
-+mailcmd = mail -E 'set escape' -s
- # Default name of the chain
- #
---- a/config/action.d/mail-whois.conf
-+++ b/config/action.d/mail-whois.conf
-@@ -20,7 +20,7 @@ norestored = 1
- actionstart = printf %%b "Hi,\n
-               The jail <name> has been started successfully.\n
-               Regards,\n
--              Fail2Ban"|mail -s "[Fail2Ban] <name>: started on <fq-hostname>" <dest>
-+              Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: started on <fq-hostname>" <dest>
- # Option:  actionstop
- # Notes.:  command executed at the stop of jail (or at the end of Fail2Ban)
-@@ -29,7 +29,7 @@ actionstart = printf %%b "Hi,\n
- actionstop = printf %%b "Hi,\n
-              The jail <name> has been stopped.\n
-              Regards,\n
--             Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped on <fq-hostname>" <dest>
-+             Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: stopped on <fq-hostname>" <dest>
- # Option:  actioncheck
- # Notes.:  command executed once before each actionban command
-@@ -49,7 +49,7 @@ actionban = printf %%b "Hi,\n
-             Here is more information about <ip> :\n
-             `%(_whois_command)s`\n
-             Regards,\n
--            Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip> from <fq-hostname>" <dest>
-+            Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: banned <ip> from <fq-hostname>" <dest>
- # Option:  actionunban
- # Notes.:  command executed when unbanning an IP. Take care that the
---- a/config/action.d/mail.conf
-+++ b/config/action.d/mail.conf
-@@ -16,7 +16,7 @@ norestored = 1
- actionstart = printf %%b "Hi,\n
-               The jail <name> has been started successfully.\n
-               Regards,\n
--              Fail2Ban"|mail -s "[Fail2Ban] <name>: started  on <fq-hostname>" <dest>
-+              Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: started  on <fq-hostname>" <dest>
- # Option:  actionstop
- # Notes.:  command executed at the stop of jail (or at the end of Fail2Ban)
-@@ -25,7 +25,7 @@ actionstart = printf %%b "Hi,\n
- actionstop = printf %%b "Hi,\n
-              The jail <name> has been stopped.\n
-              Regards,\n
--             Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped on <fq-hostname>" <dest>
-+             Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: stopped on <fq-hostname>" <dest>
- # Option:  actioncheck
- # Notes.:  command executed once before each actionban command
-@@ -43,7 +43,7 @@ actionban = printf %%b "Hi,\n
-             The IP <ip> has just been banned by Fail2Ban after
-             <failures> attempts against <name>.\n
-             Regards,\n
--            Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip> from <fq-hostname>" <dest>
-+            Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: banned <ip> from <fq-hostname>" <dest>
- # Option:  actionunban
- # Notes.:  command executed when unbanning an IP. Take care that the