A netfilter firewall (the kernel-level firewall on Linux, sometimes referred to as iptables firewall) can blacklist hosts dynamically. This is very useful to stop hosts from performing brute force attacks on serices that require a password, such as the ssh service.
The firewall rules below create a blacklist for ssh connections. Using the recent module, we create two tables, called sshconn and BLACKLIST. Every new ssh packet is listed in sshconn. If the number of new packets in the last 30 seconds is more than 3, the packet is redirected to the blacklistdrop chain. This chain adds the packet to the BLACKLIST, and drops the packet.
Every subsequent packet that is from a host that has been seen in BLACKLIST the last 120 seconds, updates the BLACKLIST and is dropped.
Outgoing packets to a host that has been seen in BLACKLIST the last 30 seconds are rejected using a special reject that will notify the sending process to clean up this connection. This is done in the properREJECT chain.
These are the firewall rules:
# create properREJECT chain that does different rejects for tcp/udp
iptables -N properREJECT
iptables -A properREJECT -p tcp -j REJECT --reject-with tcp-reset
iptables -A properREJECT -j REJECT --reject-with icmp-port-unreachable
#
iptables -N blacklistdrop
iptables -A blacklistdrop -j LOG --log-prefix "adding to BLACKLIST: "
iptables -A blacklistdrop -m recent --name BLACKLIST --set -j DROP
#
#
# on external hosts, do rate limiting on incoming ssh packets, and keep a blacklist for 30 seconds
# this rule drops *any* packet if the IP is in the blacklist
# icmp 'destination-unreachable' packets should not update BLACKLIST, because
# they are generated by our own REJECT rule in the extern_out chain
iptables -A extern_in -m recent --name BLACKLIST --update --seconds 120 -j DROP
#
# all *established* ssh connections simply continue
iptables -A extern_in -p tcp --dport 22 -m state --state ESTABLISHED,RELATED -j ACCEPT
#
# *new* ssh connections are all put into a list 'sshconn', and if there are 3 such packets in 30 seconds
# we send the package to chain 'blacklistdrop' which puts the IP in the blacklist
iptables -A extern_in -p tcp --dport 22 -m state --state NEW -m recent --name sshconn --rcheck --seconds 30 --hitcount 3 -j blacklistdrop
#
# if we have seen less then 3 such packets in the last 30 seconds we accept
iptables -A extern_in -p tcp --dport 22 -m state --state NEW -m recent --name sshconn --set -j ACCEPT
#
# if the destination address is in the blacklist, we REJECT *any* packet
iptables -A extern_out -m recent --name BLACKLIST --rdest --rcheck --seconds 30 -j properREJECT
#
# outgoing we accept all ssh traffic, with connection tracking
iptables -A extern_out -p tcp --sport 22 -m state --state ESTABLISHED,NEW,RELATED -j ACCEPT
The blacklist is used on several servers, and with a regular ssh brute force attack, attackers get the chance to try 2 or three passwords before they are blocked by the blacklist.