[BR]: Explicit Ban-Identifier breaks Restore after Server-Restart
Environment:
- Fail2Ban version : 1.0.2-2 / 1.1.0-8 /
masterbranch - OS, including release name/version : Debian 12.12 "bookworm" / Debian 13.1 "trixie" / Debian 13.1 "trixie"
- Fail2Ban installed via OS/distribution mechanisms
- Only the first two versions/tests. The third test against
masterbranch was directly from source (git-clone).
- Only the first two versions/tests. The third test against
- You have not applied any additional foreign patches to the codebase
- Some customizations were done to the configuration (provide details below is so)
The issue:
For a jail that explicitly specifies a Ban-Identifier regex capturing group using <F-ID>, restoring the bans after a restart of the fail2ban-server fails with an error.
Steps to reproduce
- Start fail2ban-server
- Trigger a ban (by writing the logline to the logfile)
- Stop the fail2ban-server
- Start the fail2ban-server again
Expected behavior
Upon starting the fail2ban-server again, the ban is properly restored from the database.
Observed behavior
An error occurs, preventing the ban-action from executing:
2025-10-31 12:43:25,921 fail2ban.actions [27]: ERROR Failed to execute ban jail 'my_jail' action 'dummy' info 'ActionInfo({'ip': '10.20.30.40', 'fid': <function Actions.ActionInfo.<lambda> at 0x7ff529cc0400>, 'raw-ticket': <function Actions.ActionInfo.<lambda> at 0x7ff529cc0b80>})': 'str' object has no attribute 'familyStr'
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/fail2ban/server/actions.py", line 513, in __checkBan
action.ban(aInfo)
~~~~~~~~~~^^^^^^^
File "/usr/lib/python3/dist-packages/fail2ban/server/action.py", line 562, in ban
family = aInfo.get('family', '')
File "<frozen _collections_abc>", line 811, in get
File "/usr/lib/python3/dist-packages/fail2ban/server/action.py", line 146, in __getitem__
value = value(self) if hasattr(value, '__code__') and value.__code__.co_argcount else value()
~~~~~^^^^^^
File "/usr/lib/python3/dist-packages/fail2ban/server/actions.py", line 376, in <lambda>
"family": lambda self: self['ip'].familyStr,
^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'familyStr'Any additional information
I did a bit of debugging myself. The cause appears to be the type of the ip data in the ticket is different between the initial ban-creation and the later restored-from-database. This can be seen when inspecting the ticket data in Actions.__checkBan(...) (fail2ban/server/actions.py line 495):
# Create ban
ticket.getID() type='fail2ban.server.ipdns.IPAddr' value='10.20.30.40:50'
ticket.getIP() type='fail2ban.server.ipdns.IPAddr' value='10.20.30.40'
# Restore ban
ticket.getID() type='fail2ban.server.ipdns.IPAddr' value='10.20.30.40:50'
ticket.getIP() type='str' value='10.20.30.40'Since Ticket.getIP() is apparently expected to always return a IPAddr, the following change fixes the problem. But I can't assess how "correct" this is in the grand scheme of things, which is why I created a bug report instead of a PR.
--- a/fail2ban/server/ticket.py
+++ b/fail2ban/server/ticket.py
@@ -25,7 +25,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL"
from ..helpers import getLogger
-from .ipdns import IPAddr
+from .ipdns import IPAddr, asip
from .mytime import MyTime
# Gets the instance of the logger.
@@ -96,7 +96,7 @@ class Ticket(object):
return self._id
def getIP(self):
- return self._data.get('ip', self._id)
+ return asip(self._data.get('ip', self._id))
def setTime(self, value):
self._time = valueConfiguration, dump and another helpful excerpts
Any customizations done to /etc/fail2ban/ configuration
fail2ban.local
[Definition]
loglevel = 4
logtarget = stdout
allowipv6 = nojail.d/my_jail.conf
[my_jail]
enabled = yes
filter = my_filter
logpath = /var/log/my_logfile
failregex = <F-ID><HOST>:<F-PORT/></F-ID> you did it wrong
maxretry = 1
bantime = 1d
banaction = dummyfilter.d/my_filter.conf
[Definition]
# emptyRelevant parts of /var/log/fail2ban.log file:
2025-10-31 12:43:25,713 fail2ban.jail [27]: DEBUG Starting jail 'my_jail'
2025-10-31 12:43:25,713 fail2ban.filterpyinotify[27]: DEBUG [my_jail] filter started (pyinotifier)
2025-10-31 12:43:25,713 fail2ban.filterpyinotify[27]: MSG Log presence detected for file /var/log/my_logfile
2025-10-31 12:43:25,713 fail2ban.action [27]: #09-Lev. if [ ! -z '/var/run/fail2ban/fail2ban.dummy' ]; then touch /var/run/fail2ban/fail2ban.dummy; fi;
printf %b "123\n" >> /var/run/fail2ban/fail2ban.dummy
echo "[my_jail] dummy /var/run/fail2ban/fail2ban.dummy -- started"
2025-10-31 12:43:25,714 fail2ban.filter [27]: DEBUG Seek to find time 1761914005.7141564 (2025-10-31 12:33:25), file size 58
2025-10-31 12:43:25,714 fail2ban.filter [27]: DEBUG Position -1 from 58, found time None () within 0 seeks
2025-10-31 12:43:25,719 fail2ban.utils [27]: #09-Lev. 7ff52a6cbee0 -- exec: if [ ! -z '/var/run/fail2ban/fail2ban.dummy' ]; then touch /var/run/fail2ban/fail2ban.dummy; fi;
printf %b "123\n" >> /var/run/fail2ban/fail2ban.dummy
echo "[my_jail] dummy /var/run/fail2ban/fail2ban.dummy -- started"
2025-10-31 12:43:25,719 fail2ban.utils [27]: DEBUG 7ff52a6cbee0 -- stdout: '[my_jail] dummy /var/run/fail2ban/fail2ban.dummy -- started'
2025-10-31 12:43:25,720 fail2ban.utils [27]: DEBUG 7ff52a6cbee0 -- returned successfully 0
2025-10-31 12:43:25,721 fail2ban.actions [27]: HEAVY Actions: wait for pending tickets 2 (default 2)
2025-10-31 12:43:25,721 fail2ban.jail [27]: INFO Jail 'my_jail' started
2025-10-31 12:43:25,721 fail2ban [27]: HEAVY OK : None
2025-10-31 12:43:25,721 fail2ban.transmitter [27]: HEAVY Command: ['server-status']
2025-10-31 12:43:25,721 fail2ban.transmitter [27]: DEBUG Status: ready
2025-10-31 12:43:25,721 fail2ban [27]: HEAVY OK : 'Server ready'
2025-10-31 12:43:25,721 fail2ban.beautifier [27]: HEAVY Beautify 'Server ready' with ['server-status']
Server ready
2025-10-31 12:43:25,921 fail2ban.actions [27]: NOTICE [my_jail] Restore Ban 10.20.30.40:50
2025-10-31 12:43:25,921 fail2ban.actions [27]: ERROR Failed to execute ban jail 'my_jail' action 'dummy' info 'ActionInfo({'ip': '10.20.30.40', 'fid': <function Actions.ActionInfo.<lambda> at 0x7ff529cc0400>, 'raw-ticket': <function Actions.ActionInfo.<lambda> at 0x7ff529cc0b80>})': 'str' object has no attribute 'familyStr'
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/fail2ban/server/actions.py", line 513, in __checkBan
action.ban(aInfo)
~~~~~~~~~~^^^^^^^
File "/usr/lib/python3/dist-packages/fail2ban/server/action.py", line 562, in ban
family = aInfo.get('family', '')
File "<frozen _collections_abc>", line 811, in get
File "/usr/lib/python3/dist-packages/fail2ban/server/action.py", line 146, in __getitem__
value = value(self) if hasattr(value, '__code__') and value.__code__.co_argcount else value()
~~~~~^^^^^^
File "/usr/lib/python3/dist-packages/fail2ban/server/actions.py", line 376, in <lambda>
"family": lambda self: self['ip'].familyStr,
^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'familyStr'
2025-10-31 12:43:25,933 fail2ban.actions [27]: DEBUG Banned 1 / 1, 1 ticket(s) in 'my_jail'
2025-10-31 12:43:25,933 fail2ban.actions [27]: HEAVY Actions: wait for pending tickets 2 (default 2)Relevant lines from monitored log files:
2025-10-31T12:43:23+00:00 10.20.30.40:50 you did it wrongSource: fail2ban/fail2ban