Troubleshooting Fail2Ban: Why Banned IPs Still Connect to Postfix Server (iptables Analysis)


1 views

When examining /var/log/messages, you'll notice entries like:

Jun 19 12:09:32 localhost fail2ban.actions: INFO   [postfix] 114.43.245.205 already banned

This indicates Fail2Ban has detected repeated attack attempts from an IP that should already be blocked in iptables. Let's dissect why this happens.

First, verify your current iptables rules with:

iptables -L -n -v --line-numbers
iptables -L f2b-postfix -n -v  # Specifically check Fail2Ban chain

A proper Fail2Ban iptables setup should show:

Chain INPUT (policy ACCEPT)
target     prot opt source       destination
f2b-postfix  tcp  --  0.0.0.0/0    0.0.0.0/0    multiport dports 25,465

Chain f2b-postfix (1 references)
target     prot opt source       destination
REJECT     all  --  114.43.245.205 0.0.0.0/0    reject-with icmp-port-unreachable

Several technical reasons could explain why connections persist:

  • Chain Order Issues: If the Fail2Ban chain isn't properly referenced in INPUT/FORWARD chains
  • Port Specification: The banned IP might be connecting through non-standard ports
  • iptables Timeout: Connection tracking may maintain existing sessions

Modify your jail.local (not jail.conf) with these additions:

[postfix]
action = iptables[name=postfix, port="smtp,ssmtp,submission,587"]
         sendmail-whois[name=postfix, dest=root]

For better protection, implement multiport monitoring:

action = iptables-multiport[name=postfix, port="25,465,587"]

Create a test script to verify blocking effectiveness:

#!/bin/bash
TEST_IP="114.43.245.205"
PORT=25

# Check iptables block
if iptables -L f2b-postfix -n | grep -q $TEST_IP; then
    echo "[✓] IP found in iptables"
else
    echo "[×] IP missing from iptables"
fi

# Test connection
if nc -zv -w 2 $TEST_IP $PORT &> /dev/null; then
    echo "[!] Connection successful - block ineffective"
else
    echo "[✓] Connection blocked successfully"
fi

For persistent attackers, consider flushing conntrack:

conntrack -D -s 114.43.245.205

Or add these iptables rules before the Fail2Ban chain:

iptables -I INPUT -m conntrack --ctstate INVALID -j DROP
iptables -I INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

Enable detailed logging in your jail.local:

loglevel = DEBUG

And monitor Fail2Ban's debug output:

fail2ban-client -x start

When examining Fail2Ban logs on CentOS, you might encounter entries like:

Jun 19 12:09:32 localhost fail2ban.actions: INFO   [postfix] 114.43.245.205 already banned

This indicates Fail2Ban detected malicious activity from an IP that should theoretically be blocked in iptables. Let's break down why this happens.

Several technical scenarios can explain this behavior:

1. Chain Order Mismatch: Your iptables rules might process ACCEPT rules before REJECT/DROP
2. Multiple Network Interfaces: The ban might only apply to one interface
3. Temporary Rule Flush: Some services might reload firewall rules
4. IPTables Save/Restore Issues: Persistent rules might not be properly saved

First, verify your current iptables rules:

iptables -L -n -v --line-numbers
iptables -t nat -L -n -v --line-numbers

Pay special attention to the order of rules in your INPUT chain. A misplaced ACCEPT rule could override your Fail2Ban blocks.

Fail2Ban typically inserts rules at the top of the chain. Here's how to check:

iptables -L INPUT -n --line-numbers | grep f2b

If you see your Fail2Ban rules below permissive rules, you'll need to modify your jail.local:

[DEFAULT]
chain = INPUT
action = iptables[name=postfix, port="smtp,ssmtp", protocol=tcp, chain=INPUT]

Here's an optimized configuration for better protection:

[postfix]
enabled = true
port = smtp,ssmtp
filter = postfix
logpath = /var/log/maillog
maxretry = 2
bantime = 86400
findtime = 600
action = iptables-multiport[name=postfix, port="smtp,ssmtp", protocol=tcp]

For more reliable bans, consider these approaches:

# Method 1: Use ipset for better performance
action = iptables-ipset-proto6[name=postfix, port="smtp,ssmtp", protocol=tcp]

# Method 2: Combine with TCP wrappers
action = iptables-tcpwrapper[name=postfix, port="smtp,ssmtp"]

# Method 3: Multi-layer protection
action = %(action_)s
         %(action_mwl)s
         %(action_route)s

After making changes, always:

fail2ban-client reload postfix
fail2ban-client status postfix

Monitor your logs in real-time to confirm bans are working:

tail -f /var/log/fail2ban.log | grep -i ban