The recent module in iptables allows you to track and limit connection attempts from specific IP addresses, making it a powerful tool for dynamically blocking repeat offenders like brute-force attackers.
Let’s see it in action. Imagine you’re seeing a flood of failed SSH login attempts from a particular IP, say 192.168.1.100. You want to temporarily ban this IP from even attempting to connect to your SSH port (22) after a few tries.
Here’s a common iptables rule set that accomplishes this:
# Clear existing rules (use with extreme caution on production systems!)
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -t raw -F
iptables -t raw -X
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
# Allow established and related connections
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow loopback traffic
iptables -A INPUT -i lo -j ACCEPT
# Allow SSH from specific trusted IPs (example)
iptables -A INPUT -p tcp --dport 22 -s 192.168.1.1 -j ACCEPT
# Track IPs attempting to connect to SSH
# -A INPUT: Append this rule to the INPUT chain
# -p tcp --dport 22: Match TCP packets destined for port 22
# -m recent --set --name SSH_ATTACKERS: Use the 'recent' module, set a name 'SSH_ATTACKERS' for this IP
# --state NEW: Only match new connection attempts
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --set --name SSH_ATTACKERS
# Create a list of IPs that have recently connected to SSH
# -A INPUT: Append to INPUT chain
# -p tcp --dport 22: Match TCP packets destined for port 22
# -m recent --name SSH_ATTACKERS: Match IPs currently in the 'SSH_ATTACKERS' list
# --update: Update the timestamp for the IP if it's already in the list
# --seconds 300: If the IP has been seen in the last 300 seconds (5 minutes)
# --hitcount 5: AND has been seen at least 5 times
# -j LOG --log-prefix "SSH Brute-Force: " : Log the event
# -j DROP: Then drop (block) the connection
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --name SSH_ATTACKERS --update --seconds 300 --hitcount 5 -j LOG --log-prefix "SSH Brute-Force: "
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --name SSH_ATTACKERS --update --seconds 300 --hitcount 5 -j DROP
# Allow all other traffic (adjust this based on your security needs)
iptables -A INPUT -j ACCEPT
In this example:
- We first allow established connections and loopback traffic.
- We then create a rule (
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --set --name SSH_ATTACKERS) that, for any new TCP connection attempt to port 22, adds the source IP address to a list namedSSH_ATTACKERS. This rule simply records the IP. - The crucial part is the next set of rules:
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --name SSH_ATTACKERS --update --seconds 300 --hitcount 5 -j LOG --log-prefix "SSH Brute-Force: "iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --name SSH_ATTACKERS --update --seconds 300 --hitcount 5 -j DROPThese rules check if the new TCP connection attempt to port 22 is from an IP address already in theSSH_ATTACKERSlist. If it is, and if that IP has appeared in the list at least 5 times (--hitcount 5) within the last 300 seconds (--seconds 300), then the connection is logged and subsequently dropped. The--updateflag is key here; it resets the timer for an IP if it’s seen again within the grace period, effectively extending the ban duration if the attack continues.
The recent module maintains an in-memory list of IP addresses and their timestamps. When a packet matches the rule, iptables checks if the source IP is in the named list. If it is, and the --update flag is used, it refreshes the timestamp for that IP. The --seconds and --hitcount parameters then determine if the IP has exceeded the threshold for being considered an offender. If it has, the specified target (LOG and DROP in this case) is executed.
To inspect the recent module’s lists, you can use:
iptables -m recent --name SSH_ATTACKERS --list
This will show you the IPs currently in the SSH_ATTACKERS list, along with their timestamps and hit counts. You can clear the list with:
iptables -m recent --name SSH_ATTACKERS --flush
A common pitfall is not understanding how --update interacts with --seconds and --hitcount. If an IP exceeds the hit count within the time window, it gets blocked. Each subsequent new connection attempt from that IP within the time window will re-trigger the --update and reset the 300-second timer. This means the IP stays banned for 300 seconds from its last attempt, not from the first time it was banned.
The next problem you’ll likely encounter is managing the persistence of these iptables rules across reboots, which usually involves tools like iptables-persistent or firewalld.