== Quick notes on the Linux iptables 'ipset' extension For a long time Linux's iptables firewall had an annoying lack in that it had no way to do efficient matching against a set of IP addresses. If you had a lot of IP addresses to match things against (for example if you were firewalling hundreds or thousands of IP addresses and IP address ranges off from your SMTP port), you needed one iptables rule for each entry and then they were all checked sequentially. This didn't make your life happy, to put it one way. In modern Linuxes, [[ipsets http://ipset.netfilter.org/]] are finally the answer to this; they give you support for efficient sets of various things, including random CIDR netblocks. ([[This entry http://daemonkeeper.net/781/mass-blocking-ip-addresses-with-ipset/]] suggests that ipsets only appeared in mainline Linux kernels as of 2.6.39. Ubuntu 12.04, 14.04, Fedora 20, and RHEL/CentOS 7 all have them while RHEL 5 appears to be too old.) To work with ipsets, the first thing you need is the user level tool for creating and manipulating them. For no particularly sensible reason your Linux distribution probably doesn't install this when you install the standard iptables stuff; instead you'll need to install an additional package, usually called _ipset_. Iptables itself contains the code to use ipsets, but without _ipset_ to create the sets you can't actually install any rules that use them. (I wish I was kidding about this but I'm not.) The basic use of ipsets is to make a set, populate it, and match against it. Let's take an example: .pn prewrap on > ipset create smtpblocks hash:net counters > ipset add smtpblocks 27.112.32.0/19 > ipset add smtpblocks 204.8.87.0/24 > iptables -A INPUT -p tcp --dport 25 -m set --match-set smtpblocks src -j DROP (Both entries are currently on [[the Spamhaus EDROP list http://www.spamhaus.org/drop/]].) Note that the set must exist before you can add iptables rules that refer to it. The _ipset_ manpage has a long discussion of the various types of sets that you can use and the _iptables-extensions_ manpage has a discussion of _--match-set_ and the _SET_ target for adding entries to sets from iptables rules. The _hash:net_ I'm using here holds random CIDR netblocks (including /32s, ie single hosts) and is set to have counters. It would be nice if there was a simple command to get just a listing of the members of an ipset. Unfortunately there isn't, as plain '_ipset list_' insists on outputting a few lines of summary information before it lists the members. Since I don't know if these are constant I'm using '_ipset list -t save | grep "^add "_', which seems ugly but seems likely to keep working forever. Unfortunately I don't think there's an officially supported and documented _ipset_ command for adding multiple entries into a set at once in a single command invocation; instead you're apparently expected to run '_ipset add ..._' repeatedly. You can abuse the '_ipset restore_' command for this if you want to by creating appropriately formatted input; check the output of '_ipset save_' to see what it needs to look like. This may even be considered a stable interface by the _ipset_ authors. Ipset syntax and usage appears to have changed over time, so old discussions of it that you find online may not work quite as written (and someday these notes may be out of date that way as well). PS: I can sort of see a lot of clever uses for ipsets, but I've only started exploring them right now and my iptables usage is fairly basic in general. I encourage you to read the _ipset_ manpage and go wild. === Sidebar: how I think you're supposed to use list sets As an illustrated example: > ipset create spamhaus-drop hash:net counters > ipset create spamhaus-edrop hash:net counters > [... populate both from spamhaus ...] > > ipset create spamhaus list:set > ipset add spamhaus spamhaus-drop > ipset add spamhaus spamhaus-edrop > > iptables -A INPUT -p tcp --dport 25 -m set --match-set spamhaus src -j DROP This way your iptables rules can be indifferent about exactly what goes into the 'spamhaus' ipset, although of course this will be slightly less efficient than checking a single merged set.