Firewalls are fun, but just dropping all the bad packets is fairly boooring.
Enter iptables TARPIT support (very nicely introduced by this article): accept TCP connection, then keep sending window = 0 ACKs, totally ignoring connection teardown requests.
Voila, sticky like flypaper. Good for all the portscanning fools out there.
Now, actually getting this stuff working is not absolutely trivial, though, depending on your platform of choice.
First thing is to realise that both kernel as well as the iptables program need that support compiled in. The netfilter guys use a system called Patch-o-Matic to organise these extras, but that thing sucks a bit IMHO.
For the iptables proggie you can be a Cheap Bastard and just get the Debian
version 1.2.9-X or better, as the maintainer has already applied a whole lot
of Patch-o-Matic extras. Look for
if you have that, you're ready on that front.
For kernel support you'll have to build your own kernel with the extras patched in. As I don't like the Patch-o-Matic thingie, I've extracted the relevant bits and pieces into a traditional patch for 2.4.X which you can grab here. Reconfigure with the TARPIT target enabled and rebuild.
The actual use of TARPIT is trivial:
iptables -A somechain -p tcp -j TARPIT just before your normal
DROP does the job. You can of course be more specific in what to tarpit, but
I like the blanket "deny-by-default"...don't forget
-p tcp or
iptables will reject your rule (tarpitting makes only sense for TCP;
the tarpit rule is only augmenting your main drop-all rull, not replacing it).
So far, so good.
When I fired that rule up on my Sun U1 firewall system, I noticed the load going up pretty badly as I logged every dropped packet, the normal (LOG) way. This is pretty bad as it catches every single tarpitted retry packet, and LOG goes kernel--->klogd--->syslogd--->wherever, which means lotsa context switches.
One answer to that problem can be using ULOG and the ulogd to do the logging in userspace, buffered and with a lot less nasty load effects. The ULOG target can buffer multiple packets to be logged and burst them (or fractions of them) to a recipient program later on. Pretty nice idea, all in all.
However, don't try it on a box where the kernel is 64 bit and userland is 32 bit (as is the case with Linux on UltraSPARCs): many programs interfacing with the kernel do not properly grok the sizing differences for kernel-related datastructures and fall flat on their faces.
Iptables is one of those: the ULOG target does not work (unless you build the software on a 64/32 system...see Bug 232401).
Ok, thinks I, let's just rate-limit the log lines then, with the "limit" extension which is mainstream. Gotcha! Same problem: up to 1.2.10-something, iptables' limit support does not work at all on 64/32 boxes. Great.
Later I got the ULOG kernel environment working, only to discover that ulogd, the userland daemon, is FUBAR'd on 64/32 systems, too...
In the end I decided not to log any dropped packets for the time being.
Two more issues: you definitely spend a little more network bandwith on fooling the idiots out there, but that's well spent IMnsHO.
The other thing is that connection tracking is supposed to interact badly
with tarpitting as some connection state memory is wasted on the tarpitted
connections. However obvious and logical that may be, I couldn't reproduce
this on my boxes at all:
/proc/net/ip_conntrack doesn't show
any of the tarpitted connections at all, ever. This means that right now I
have no means of seeing who's stuck - but that I can live with very well.