Firewalling lists of compromised hosts

For a few days, on and off my mail server has been alerting with connection issues. Digging deeper I found that one of the blocklists I use to prevent compromised hosts connecting was having issues via DNS.

Eventually I managed to get on to their website but didn’t see any mention of a problem, however I did notice they provided downloads for their lists. Initially I was considering using their rbldns zone files to create my own RBL service but a bit of research pointed me towards ipset to use a list of CIDR ranges in iptables.

After installing ipset I discovered there was something missing in the kernel, I was half expecting this with my custom gentoo kernel. Fortunately gentoo has some nice documentation which even included an example script I could modify.

Kernel settings for ipset

[*] Networking support  --->
    Networking options  --->
    [*] Network packet filtering framework (Netfilter) --->
        <M>  IP set support --->

as well as
             Core Netfilter Configuration --->       
                <M>  set target and match support

So a kernel rebuild and reboot later and ready to go with a script. I opted for the allinone blocklist, it’s a bit more work but allows an option in the future to exclude certain listing reasons.

#!/bin/sh
opt="hash:net --hashsize 64"
datadir=/var/lib/ipset
target=https://lists.blocklist.de/lists/dnsbl/allinone.list
wget -qNP $datadir $target || exit
set=allinone.list
tmp=${set}-tmp
ipset create $tmp $opt
networks="$(grep -E '^[0-9]' $datadir/$set | sed -rne 's/(^([0-9]{1,3}\.){3}[0-9]{1,3}).*$/\1/p' | sort | uniq)"
for i in $networks; do
    ipset add $tmp ${i}
done
ipset create -exist $set $opt &&
ipset swap $tmp $set &&
ipset destroy $tmp &&
unset -v i networks opt set tmp

This script lives in /etc/cron.hourly/ to keep it updated hourly.

All that was left for me to do was update my iptables saved rules file, for me this is /var/lib/iptables/rules-save but can be different per OS. I decided to add the rule fairly high up and regardless of the traffic type, anything from listed IPs is dropped. I tend to drop packets when I don’t want them so I don’t send an icmp-reject and it slows the source down as it’s to time out most connection attempts.

-A INPUT -i eth0 -m set --match-set allinone.list src -j DROP

I typically add -m comment --comment "Something" but when viewing the rule it’s self explanitory. I could restart iptables, fail2ban etc but historically I’ve preferred to test a full reboot of the box. One reboot later and iptables -L -n -v is showing the rule in place and packets being matched.

After some time with the rule in place.

Chain INPUT (policy DROP 523 packets, 33887 bytes)
 pkts bytes target     prot opt in     out     source               destination
...
1414K   82M DROP       all  --  eth0   *       0.0.0.0/0            0.0.0.0/0            match-set allinone.list src
...