EDIT: added additional .conf filer and slightly changed wording as suggested by Marco
I'm running Fail2ban v0.10 which is supposed to support IPv6.
I've set up Fail2ban with nftables according to these instructions, with the exception that I used the 'inet' family for nftables instead of the ip family because I'd like to allow IPv6 traffic to my server.
The server is reachable over IPv6 and my firewall (nftables) seems to be configured correctly as far as I can see (the table inet filter).
However the 'table inet fail2ban' is why I'm making this post, it seems to me Fail2ban only reads the IPv4 logs, and blocks offending IPv4 hosts.
Am I reading this right? If so does anyone know how I can make Fail2ban work with IPv6 traffic as well? I know the Fail2ban v0.10 changelog states that not all ban-actions are IPv6 capable yet, but I can't seem to find a list.
A link to where I could finde the info is welcome as well, because I couldn't seem to finde that myself.
I've only included the recidive jail configs because I assume that if I can get jail to work with IPv6, I can do the same with the others, if I'm mistaken with that assumption please do tell me :)
My nftables ruleset:
table inet filter {
chain input {
type filter hook input priority 0; policy accept;
ct state { related, established} accept
ct state invalid drop
iifname "lo" accept
ip protocol icmp accept
ip6 nexthdr ipv6-icmp accept
tcp dport ssh accept
tcp dport http accept
tcp dport https accept
limit rate 5/minute burst 5 packets counter packets 972 bytes 56710 log prefix " denied: " level debug
drop
}
chain forward {
type filter hook forward priority 0; policy accept;
drop
}
chain output {
type filter hook output priority 0; policy accept;
accept
}
}
table inet fail2ban {
set f2b-sshd {
type ipv4_addr
}
set f2b-nginx-botsearch {
type ipv4_addr
}
set f2b-recidive {
type ipv4_addr
}
chain INPUT {
type filter hook input priority 100; policy accept;
ip protocol hopopt-reserved ip saddr @f2b-recidive drop
tcp dport { http, https} ip saddr @f2b-nginx-botsearch drop
tcp dport { ssh} ip saddr @f2b-sshd drop
}
}
/etc/nftables/fail2ban.conf
#!/usr/sbin/nft -f
table inet fail2ban {
chain INPUT {
type filter hook input priority 100;
}
}
/etc/nftables.conf
#!/usr/bin/nft -f
table inet filter {
chain input {
type filter hook input priority 0;
ct state {established, related} accept
ct state invalid drop
iifname lo accept
ip protocol icmp accept
ip6 nexthdr icmpv6 accept
tcp dport ssh accept
tcp dport http accept
tcp dport https accept
limit rate 5/minute burst 5 packets counter packets 0 bytes 0 log prefix " denied: " level debug
drop
}
chain forward {
type filter hook forward priority 0;
drop
}
chain output {
type filter hook output priority 0;
accept
}
}
include "/etc/nftables/fail2ban.conf"
/etc/fail2ban/action.d/nftables-common.local
[Init]
nftables_family = inet
nftables_table = fail2ban
blocktype = drop
nftables_set_prefix =
/etc/fail2ban/jail.local
[INCLUDES]
before = paths-arch.conf
[DEFAULT]
ignorecommand =
bantime = 1h
findtime = 10m
maxretry = 5
usedns = warn
logencoding = auto
enabled = false
filter = %(__name__)s
protocol = tcp
chain = INPUT
port = 0:65535
fail2ban_agent = Fail2Ban/%(fail2ban_version)s
banaction = nftables-multiport
banaction_allports = nftables-allports
action_mw = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
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=%(logpath)s, chain="%(chain)s"]
action_xarf = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath=%(logpath)s, port="%(port)s"]
action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"]
%(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
action_blocklist_de = blocklist_de[email="%(sender)s", service=%(filter)s, apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
action_badips = badips.py[category="%(__name__)s", banaction="%(banaction)s", agent="%(fail2ban_agent)s"]
action_badips_report = badips[category="%(__name__)s", agent="%(fail2ban_agent)s"]
action_abuseipdb = abuseipdb
action = %(action_)s
[sshd]
enabled = true
mode = normal
filter = sshd[mode=%(mode)s]
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
[nginx-botsearch]
enabled = true
port = http,https
logpath = %(nginx_error_log)s
maxretry = 2
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
banaction = %(banaction_allports)s
bantime = 1w
findtime = 1d
maxretry = 3
protocol = 0-255
/etc/fail2ban/filter.d/recidive.conf
[INCLUDES]
before = common.conf
[Definition]
_daemon = fail2ban\.actions\s*
_jailname = recidive
failregex = ^(%(__prefix_line)s| %(_daemon)s%(__pid_re)s?:\s+)NOTICE\s+\[(?!%(_jailname)s\])(?:.*)\]\s+Ban\s+<HOST>\s*$
ignoreregex =
[Init]
journalmatch = _SYSTEMD_UNIT=fail2ban.service PRIORITY=5
/etc/fail2ban/filter.d/common.conf
[DEFAULT]
_daemon = \S*
__pid_re = (?:\[\d+\])
__daemon_re = [\[\(]?%(_daemon)s(?:\(\S+\))?[\]\)]?:?
__daemon_extra_re = \[ID \d+ \S+\]
__daemon_combs_re = (?:%(__pid_re)s?:\s+%(__daemon_re)s|%(__daemon_re)s%(__pid_re)s?:?)
__kernel_prefix = kernel: \[ *\d+\.\d+\]
__hostname = \S+
__md5hex = (?:[\da-f]{2}:){15}[\da-f]{2}
__bsd_syslog_verbose = <[^.]+\.[^.]+>
__vserver = @vserver_\S+
__date_ambit = (?:\[\])
__prefix_line = %(__date_ambit)s?\s*(?:%(__bsd_syslog_verbose)s\s+)?(?:%(__hostname)s\s+)?(?:%(__kernel_prefix)s\s+)?(?:%(__vserver)s\s+)$
__pam_auth = pam_unix
datepattern = {^LN-BEG}