Iptables (1.4)

This IPTables script is written from the perspective of someone who manages a pair of massive web forums and a dozen smaller ones, with highly committed users. If something goes wrong, I find out about it relatively soon - either directly or from the user's friends. Alternately, if I see something is going wrong - something that appears to be abusive - I can go over the problem with the member in question.

Obviously, if you are not running a website or similar Internet service, this will be of limited use for you. There is probably still some information you can take from this, however.

I see a lot of people making 'strict' firewalls. I know for a fact that if your firewall is draconian, you will be blocking valid, perfectly harmless traffic from legitimate visitors to your website, possibly frustrating them and turning away genuine human beings. This configuration still occasionally trips on valid users, but it is rare, they are still able to use my sites, and the situation it prevents (opening a crazy number of connections) is a genuine problem that is worth addressing.

Important Notes
I explain some of these issues in the scripts proper, but I think they deserve more attention.

VPS and Control Panel Users
Proceed with a bit of caution. This is still a useful script, but back when I was still using cPanel and VPSes - not always at the same time - I had to make additional modifications for each. I do not know what has changed in the intervening years, so I cannot make good recommendations about what needs gutting. For certain, cPanel does not like it when you gut their license verification.

limit vs. hashlimit vs. connlimit
The short of it is, if you are using limit in your IPTables ruleset, you are probably doing it wrong. I have seen some people bragging about their rules, and doing things like limiting SYN packets to 20 per second - or less - using limit.

This means that, if any combination of hosts, anywhere on the Internet, sends the victim 20 SYN packets per second, no one else can open a TCP connection until the table holding that rule gets cleared. Limit is just that, a limit in total across the entirety of your system.

What most people think limit works like is a proper hashlimit declaration. I go into more detail in the script itself, but if you are only skimming to see what to grab for your own firewall rules, do not skip the hashlimit section.

For connlimit, while the documentation states that it is 'parallel connections', I have a suspicion that when IPTables breaks, what it considers to be a connection is not necessarily what the other side thinks is a connection. Be careful about setting it too low, even for a small site. The 256 to report/512 to block is based on what my members have managed to generate individually, and it was nothing special with how much they actually used my site, nor was it a lot of people behind a NAT or even one person using multiple browsers. One person, one browser, 300 conntrack entries. For awhile, AoL proxies were also a problem, though this has not been an issue in years.

I tend to think of connlimit as a means to mitigate a single-user DOS. Better than nothing. In any case, stuff like SYN floods are best handled via your sysctl.conf settings, and many of the defaults work okay there.

INVALID
Dropping all INVALID packets also drops a lot of packets from valid users of your services, and if someone has a poor connection to your website, this may make that problem even worse. Just because IPTables is confused - something that happens often - does not mean that the traffic is actually bad. The rules I have set cover the overwhelming majority of legitimate goofs that may crop up.

To be fair, surveying user experience in this regard is difficult. "Do things seem to be working smoother now?" "Yes, I think so..."

Regardless, I have had no negative result from accepting INVALID packets, at least in limited quantities. The script does start preferentially dropping invalid traffic once it gets to a lot of connections.

ICMP
For some reason, pings now have an established connection. I have accounted for this below, but outright accept RELATED ICMP incoming requests, which covers every non-ping ICMP request that you should see incoming.

UDP
Most UDP traffic gets dropped by default here. This includes traceroutes. Windows will fall back to ICMP, but you may need to let *nix users know they should use the -I switch. The ICMP rules have been loosened to make this go smoothly.

Preparation
The first thing you should do, is make a reset script that runs at a regular interval through cron or somesuch. This way, if (or rather when), you make a mistake, you only have to wait a short while rather than digging out KVM details. Or worse, paying your host for it if you do not have a virtual solution. Adjust the path as needed, of course.

Additionally, some IPTables settings can only be configured through modprobe - may as well set them now.

iptreset.sh
/sbin/iptables -F /sbin/iptables -X /sbin/iptables -t raw -F /sbin/iptables -t raw -X /sbin/iptables -P INPUT ACCEPT /sbin/iptables -P FORWARD ACCEPT /sbin/iptables -P OUTPUT ACCEPT /sbin/ip6tables -F /sbin/ip6tables -X /sbin/ip6tables -t raw -F /sbin/ip6tables -t raw -X /sbin/ip6tables -P INPUT ACCEPT /sbin/ip6tables -P FORWARD ACCEPT /sbin/ip6tables -P OUTPUT ACCEPT
 * 1) !/bin/sh

/etc/modprobe.d/iptables.conf
options xt_recent ip_list_tot=4095 options xt_recent ip_pkt_list_tot=64 options nf_conntrack expect_hashsize=65536
 * 1) General modprobe config items for iptables.
 * 2) The default is to only store 100 entries per recent table in /proc/net/ipt_recent/
 * 3) Since we expect to be able to handle a larger DDOS than that, let's up it.
 * 1) This should be tuned up or down based on the number of recent matches needed.
 * 2) Default is 20
 * 1) Can't set the bucket size/max in sysctl.conf, has to be done here.

Using these scripts
The scripts can be found at Github: https://github.com/Vekseid/Tablewall

If you're not using the tools in e.g. CentOS to save/restore rules and the associated tracking entries, you will probably want to load them at bootup. Add

pre-up /root/firewall.sh

(or whatever you named/placed it) to your main ipv4 interface declaration in /etc/network/interfaces, and

pre-up /root/firewall6.sh

to your main ipv6 interface declaration, likewise.