A machine connected to the Internet that isn’t behind a firewall is a disaster waiting to happen. And you won’t have to wait long. A recent study by the Internet Storm Center has shown that unpatched Windows computers only lasted 20 minutes before they were infected by some malware. If you’re running Linux, you’re going to have more time, but something bad is bound to happen. The most likely outcome of being out there unprotected is a denial of service attack. Script kiddies are not picky about whose machine they knock off line. If fact, most of these young cyber hoodlums don’t even know how how they’re able to do it. They just know that the cute toys they download will do it. If you don’t want to have your box at the mercy of some anti-social kid who bathes much less frequently than you, it’s time to learn how to get a firewall going.
Netfilter and iptables
The best tool currently available to create a firewall is the Netfilter/iptables combination. Netfilter is software that works with the kernel in order to control network packets. iptables lets you create rules to filter packets and packet content based on a number of criteria. You will need to install the iptables package. This is available as an RPM on Fedora based systems, as a Debian package and, of course, in the source code form from: http://www.netfilter.org/
Packet filtering involves the kernel directly, so that means that we’re going to have to configure and compile a new kernel to get it working. Although the latest major Linux distributions usually give you a kernel with some Netfilter options enabled, a person with advanced Linux knowledge should really get in there and give it a few extra tweaks. We won’t go into all the steps to compiling a kernel here, but we will show you the options you need to enable in order to run your firewall with Netfilter/iptables.
At the time of this writing, the latest major version of the kernel is 5.5. The kernel settings we talk about will be referring to this kernel.
At this point, you should have downloaded the latest version of the 5.5 kernel from http://www.kernel.org. I find the easiest way to configure the kernel is to use the command: make menuconfig This brings up the traditional interface based on ncurses. There are other more modern looking interfaces to the kernel configuration tools, but I find this one the best (and frankly, I’m used to it). If you have experience compiling kernel versions previous to this one, the options related to iptables/Netfilter might be a little harder to find, but they’re there. In the main menu, just follow: Device Drivers —> Networking support —> Networking options —> Network packet filtering (replaces ipchains) —> IP: Netfilter Configuration —> and there you’ll find the mail options. In my experience, I have found that most of the options we need are selected as modules by default. If they aren’t, you can either select them as modules (m) or have them built into the kernel (*).
Now you’re ready to build the new kernel. For those of you familiar with the 5.4 series and earlier, when you build a 5.5 kernel, there is no longer a ‘make dep’ command. We go straight to build with ‘make bzImage’. Assuming you haven’t got any errors, when you’ve finished compiling, do ‘make modules’ and ‘make modules_install’ to both compile and install those options you compiled as modules. Now place your new kernel in /boot and depending on whether you use ‘grub’ or ‘lilo’, make the appropriate changes in grub.conf or lilo.conf. Those who use ‘lilo’ should type ‘lilo’ at this point to ready the new kernel for use.
Starting with iptables
We assume now that you’ve rebooted and you’re all set to go with your new kernel. To start off, let’s try a very simple command to list the firewall rules you currently have on your system. At this point, there shouldn’t be any rules active, so running this command:
should show you output like this:
Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination
This essentially means that you’re not running a firewall. This isn’t good, so we need to get some basic rules running so you’re not vulnerable to attack.
A Simple Firewall Script
Below you’ll find a simple firewall script. It contains explanatory comments for every rules. Study it for a bit and then we’ll discuss it after.
#!/bin/sh IPTABLES=/sbin/iptables # start by flushing the rules -F ## allow packets coming from the machine -A INPUT -i lo -j ACCEPT -A OUTPUT -o lo -j ACCEPT # allow outgoing traffic -A OUTPUT -o eth0 -j ACCEPT # block spoofing -A INPUT -s 127.0.0.0/8 -i ! lo -j DROP -A INPUT -s 192.168.0.3 -j DROP # stop bad packets -A INPUT -m state --state INVALID -j DROP # NMAP FIN/URG/PSH /sbin/iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP # stop Xmas Tree type scanning /sbin/iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL ALL -j DROP /sbin/iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP # stop null scanning /sbin/iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL NONE -j DROP # SYN/RST /sbin/iptables -A INPUT -i eth0 -p tcp --tcp-flags SYN,RST SYN,RST -j DROP # SYN/FIN /sbin/iptables -A INPUT -i eth0 -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP # stop sync flood /sbin/iptables -N SYNFLOOD /sbin/iptables -A SYNFLOOD -p tcp --syn -m limit --limit 1/s -j RETURN /sbin/iptables -A SYNFLOOD -p tcp -j REJECT --reject-with tcp-reset /sbin/iptables -A INPUT -p tcp -m state --state NEW -j SYNFLOOD # stop ping flood attack /sbin/iptables -N PING /sbin/iptables -A PING -p icmp --icmp-type echo-request -m limit --limit 1/second -j RETURN /sbin/iptables -A PING -p icmp -j REJECT /sbin/iptables -I INPUT -p icmp --icmp-type echo-request -m state --state NEW -j PING ################################# ## What we allow ################################# # tcp ports # smtp -A INPUT -p tcp -m tcp --dport 25 -j ACCEPT # http -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT # pop3 -A INPUT -p tcp -m tcp --dport 110 -j ACCEPT # imap -A INPUT -p tcp -m tcp --dport 143 -j ACCEPT # ldap -A INPUT -p tcp -m tcp --dport 389 -j ACCEPT # https -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT # smtp over SSL -A INPUT -p tcp -m tcp --dport 465 -j ACCEPT # line printer spooler -A INPUT -p tcp -m tcp --dport 515 -j ACCEPT # cups -A INPUT -p tcp -m tcp --dport 631 -j ACCEPT ## restrict some tcp things ## # ssh -A INPUT -p tcp -m tcp -s 192.168.0.0/16 --dport 22 -j ACCEPT # samba (netbios) -A INPUT -p tcp -m tcp -s 192.168.0.0/16 --dport 137:139 -j ACCEPT # ntop -A INPUT -p tcp -m tcp -s 192.168.0.0/16 --dport 3000 -j ACCEPT # Hylafax -A INPUT -p tcp -m tcp -s 192.168.0.0/16 --dport 4558:4559 -j ACCEPT # webmin -A INPUT -p tcp -m tcp -s 192.168.0.0/16 --dport 10000 -j ACCEPT # udp ports # DNS -A INPUT -p udp -m udp --dport 53 -j ACCEPT # DHCP -A INPUT -p udp -m udp --dport 67:68 -j ACCEPT # NTP -A INPUT -p udp -m udp --dport 123 -j ACCEPT # SNMP -A INPUT -p udp -m udp --dport 161:162 -j ACCEPT ## restrict some udp things ## # Samba (Netbios) -A INPUT -p udp -m udp -s 192.168.0.0/16 --dport 137:139 -j ACCEPT -A INPUT -p udp -m udp --sport 137:138 -j ACCEPT # finally - drop the rest /sbin/iptables -A INPUT -p tcp --syn -j DROP
In the first part of the script, what we do is handle the ‘administrative’ tasks of the firewall. These include, as you can see from the comments, flushing the rules, to rid the system of any leftover rules that may conflict with the ones in the firewall script. After, we let packets move freely if generated by the machine itself (indicated by ‘lo’ or localhost). Then we allow packets to leave the machine on our network card (in this case, eth0).
Next, we start to prevent some of the most common network vulnerabilities. The first one is spoofing, or the ability to make packets appears as if they’re coming from your machine or your network. As it’s common practice to be a bit more tolerant toward those on your own network, those intent on breaking in will first try the spoofing routine. Next, we block any bad packets – period. Another way of attacking a network is to overwhelm it with junk. Here we’ll control this. To end off this section of the firewall, we’ve added protection against various popular attack methods such as the so-called ‘ping of death’, syn-fin attacks and others mentioned in the comments.
The second part of the firewall deals with allowing and controlling access to certain services running on the machine. The comments above each rule show which services are dealt with with each one. We control access to both tcp and udp traffic. Some services are offered to the public and some are not. You will note that toward the end, we restrict access to ssh, samba and some others to the local network. In this particular case, no one from the outside should have access to those and in your case you may choose to limit more or fewer services but the point is that iptables also offers us the possibility of doing IP address based restrictions.
Finally with the last rule we drop all packets that aren’t destined for the ports that we allow. This is a good basic rule of thumb for security. That which is not allowed is prohibited.
Though this is a basic script, it affords good protection. You may also want to enhance is and add rules. We’ll deal with that next.
What we’ve done with the script above is ‘append’ rules to the firewall as it’s loading. That’s what the ‘-A’ switch stands for. However, there may be times when you want to add rules to a running firewall. Let’s say that some lousy spammer is running a dictionary attack on you and you see from your mail server logs that he’s connecting to you from 220.127.116.11. Now, in our firewall script, we let anybody connect to our mail server (port 25). That’s only normal. You never know where mail is going to come from, so that port is generally left open to the public. However, if we see that someone’s abusing the service, like a spammer, then we can shut off his access to it so he won’t be able to connect to our mail server (until, of course, he switches his IP address). What we would do is ‘insert’ a rule into our running firewall to deal with this unforeseen situation. The rule is basically the same, but instead of the ‘-A’ option, we’ll use the ‘-I’ (for insert) option:
iptables -I INPUT -p tcp --syn -s 18.104.22.168 -j DROP
Actually, this rule doesn’t specify port 25, although that was where the trouble was coming from. This rule denies access to all packets coming to our machine coming from that IP address. That’s really what the spammer deserves. The drawback is that if there is any legitimate traffic coming from that IP address (though it’s doubtful in this case), they would be blocked. If you were able to isolate a netblock where spammers frequently operated from (from zombied PCs, for example), you could insert a rule to deal with specific ports
iptables -I INPUT -p tcp --syn -s 22.214.171.124/24 --dport 25 -j DROP
That would block connections to the mail server while preserving all of the other public services. That way, the collateral damage, so to speak, isn’t so great. We don’t want to lump the guilty in with the blameless.
Let’s say that you’ve decided to dedicate an entire machine to serving web pages. Then you’re firewall rules need to be changed. You can do this temporarily, until you’ve rebooted the machine, by first deleting the rule providing access to ports 80 and 443 and then by inserting a rule dropping packets whose destination are those ports. To delete, we use the ‘-D’ switch:
iptables -D INPUT -p tcp --dport 25 -j ACCEPT iptables -D INPUT -p tcp --dport 443 -j ACCEPT
These are the same rules that gave access to these services. We’ve just substituted the ‘-D’ switch, as you can see. Now we drop packets to those ports:
iptables -I INPUT -p tcp --dport 25 -j DROP iptables -I INPUT -p tcp --dport 443 -j DROP
Fairly Good Protection
The netfilter/iptables combination gives the machine a fighting chance when it's exposed to the outside world, but no machine is going to be 100% protected. For this reason, we still need to monitor against attacks as they happen.