Originally published January 7, 2018 @ 11:04 pm

I’ve been drinking beer and perhaps had one too many. Regardless of the reason, I felt the urge to further secure my favorite server. The target of my paranoia is once again the VSFTPd. I already have iptables and fail2ban running with various elaborate rules and filters. And this is already behind ASA and CheckPoint. In addition I wanted to place some restrictions via TCP wrappers.The first step is to add something like this to /etc/hosts.deny

vsftpd: ALL \
: spawn (/bin/logger %h denied access to %d)
: deny

The “spawn” action creates an entry in the /var/log/messages saying “<ip> denied access to vsftpd”

Then you add the allowed IPs to the /etc/hosts.allow.

Note: for CIDR notation mask use “/255.255.255.0” instead of “/24”. This is important.
vsftpd:192.168.12.0/255.255.255.0 192.168.13.0/255.255.255.0 \
192.168.120.0/255.255.255.0 192.168.121.0/255.255.255.0 \
: spawn (/bin/logger %h allowed access to %d)
: allow

The cool thing here is the spawn directive. You can have more than one and one of them can be an aggressive nmap scan, a ping flood or something even less tolerant of unwelcome visitors.

Bounce vsftpd and you should be good to go. So I went to the fridge and grabbed another beer and by the time I got back there were a couple dozen “access denied” entries in the log for the same IP from Chicago. This got me thinking that blocking that IP with iptables would probably be beneficial for the overall health of my server.

So the idea is simple: scan all current and rotated /var/log/messages*; extract unique IPs; identify the “heavy-hitters”; block them with iptables. Here’s a quick script to do this.

Note: the example below (also on GitHub) will show you the countries associated with the offending IPs. You will need to install the GeoIP package (current version is GeoIP-1.5.1-5.el6.x86_64).
#!/bin/bash
#
# Identified IPs blocked by TCP Wrappers (/etc/hosts.deny) multiple times
# and permanently block those IPs with IPTables firewall
#
m="denied access to "
t=10
whitelist="192.168.122.|192.168.123."
zgrep "${m}" /var/log/messages* | \
for ip in `grep -oE "([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})" | grep -Ev "${whitelist}" | \
sort -u -t . -k 1,1n -k 2,2n -k 3,3n -k 4,4n`
do
	n=$(zgrep -c "\b${ip} ${m}\b" /var/log/messages* | awk -F':' '{sum=sum+$NF} END {print sum}')
	if [ ${n} -ge ${t} ]
	then
		if [ `/sbin/iptables -S | grep -c "${ip}.*DROP"` -eq 0 ]
		then
			c=$(geoiplookup ${ip} | grep Country | grep -woE [A-Z]{2}, | sed 's/,//g')
			echo -e "Banning ${ip} from ${c} after ${n} TCP Wrappers denials" | tee >(logger)
			/sbin/iptables -A INPUT -s ${ip} -j DROP
		fi
	fi
done
/sbin/service iptables save

Save the script as, say, /var/adm/bin/tcpwrapper_ip_block.sh; make it executable and add this root cron job:

25 */1 * * * /var/adm/bin/tcpwrapper_ip_block.sh >/dev/null 2>&1

When someone is blocked by the script, you should see an entry in the /var/log/messages along the lines of:

Nov 11 00:58:46 thereminvox root: Banning 208.100.26.229 from US after 27 TCP Wrappers denials

The idea here is that, if someone is persistently trying to break into your FTP server, they may also decide to explore other avenues of attack. Blocking them with iptables minimizes their options.