익명 02:01

Why is my custom fail2ban action not always triggered?

Why is my custom fail2ban action not always triggered?

  • Linux Debian Trixie
  • Fail2Ban v1.1.0

cat jail.local

[DEFAULT]

backend         = systemd

destemail       = [email protected]
sender          = [email protected]
mta             = sendmail

ignoreip                = 9.9.9.9

protocol        = tcp udp
port            = 0:65535

bantime         = 1d
findtime        = 7d
bantime.rndtime         = 10000

maxretry        = 1
maxmatches      = %(maxretry)s


banaction               = nftables-multiport
banaction_allports      = nftables-allports

chain               = f2b

action_mwl              = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
             %(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath="%(backend)s", chain="%(chain)s"]


action                  = %(action_mwl)s
                          my_custom_action

enabled         = true

dbpurgeage      = 90d


[sshd]

mode            = aggressive
enabled     = true
filter      = sshd

ignoreip        = 127.0.0.1/8 ::1/128

my_custom_action, which will fail because of the last field <matches>

[Definition]
# norestored  = 1
name        = my_custom_action
actionban   = /bin/echo "<name>;<fq-hostname>;<ip>;<ip-host>;<matches>" >> my_custom_action.log

The goal is to trigger an IP lookup to get country, ASN, CIDR, etc.. info.

Before doing that, as a test I have created a simple echo "jailname, ip host fq-hostnam matches" > my_custom_action.log

This test is working partially. When I restart fail2ban (systemctl restart fail2ban) some data is in that log file. If an new IP gets banned after the restart, I get the mail notification about it, the IP is really banned (IP in the nftables chain) but the new banned IP data is not in the log.

my_custom_action.log

mx_postfix_sasl;host.domain.tld;97.211.156.184;184.sub-97-211-156.myvzw.com;2026-07-16T11:22:43.4309234+02:00 host postfix/smtpd[365934]: warning: 184.sub-97-211-156.myvzw.com[97.211.156.184]: SASL LOGIN authentication failed: (reason unavailable), sasl_username=someone@my_domain.tld
mx_postfix_sasl;host.domain.tld;97.213.107.239;239.sub-97-213-107.myvzw.com;2026-06-24T04:22:02.223489+02:00 mx1 postfix/smtpd[145679]: warning: 239.sub-97-213-107.myvzw.com[97.213.107.239]: SASL LOGIN authentication failed: (reason unavailable), sasl_username=theotherone@my_domain.tld

So, why is only some partial data in that log, or how do I set up that custom_action correctly?

Removed the last field and it seems to be working

my_custom_action (working version)

[Definition]
# norestored  = 1
name        = my_custom_action
actionban   = /bin/echo "<name>;<fq-hostname>;<ip>;<ip-host>" >> /var/log/my_custom_action.log


Top Answer/Comment:

Your custom action is firing on every ban. The mail and the nftables block are separate action entries that run independently, so them working tells you nothing about the custom one. Two bugs are breaking it:

  1. <matches> on a raw shell line. <matches> is multi-line and contains the unescaped journal text (semicolons, quotes, $, brackets, newlines). fail2ban runs your whole actionban through /bin/sh -c, so any ban whose match text carries a shell metacharacter breaks the echo, the command exits non-zero, and nothing is appended, while the ban itself still stands. That is your "partial" logging: clean matches write, messy ones don't.

  2. Relative log path. >> my_custom_action.log writes relative to fail2ban's working directory, not yours.

The entries you see after a restart aren't proof it works live. With backend = systemd a restart re-reads the journal and re-triggers actionban for rediscovered failures (hence the old 06-24/07-16 timestamps, long past your 1d bantime). Only the ones with clean match text landed in the file.

Fix: drop <matches> (you don't need it for a country/ASN lookup) and use an absolute path:

[Definition]
actionban = /bin/echo "<name>;<fq-hostname>;<ip>;<ip-host>" >> /var/log/f2b_custom.log

For the real lookup, pass fields to a script as quoted args so nothing hits the shell unquoted:

actionban = /usr/local/bin/f2b_lookup.sh "<name>" "<ip>" "<ip-host>"

Test deterministically with fail2ban-client set sshd banip 1.2.3.4, and watch /var/log/fail2ban.log. You'll see the failing action return non-zero on the bans that don't log.

상단 광고의 [X] 버튼을 누르면 내용이 보입니다