Iptables

From Noah.org
Jump to: navigation, search


Linux iptables Basic Examples

The following are simple iptables firewalls for Linux. I use these as starter firewalls when I setup a machine. I don't like using iptables-restore. I prefer to simply script the iptables commands that I would type at the command line.

Most of these scripts start by reinitializing iptables, so you will loose any rules, chains, or accounting information that iptables knows about. For example, this deletes any policies, chains, and rules in place.

iptables -P INPUT ACCEPT    # open up default policy on built-in chain
iptables -P OUTPUT ACCEPT   # open up default policy on built-in chain
iptables -P FORWARD ACCEPT  # open up default policy on built-in chain
iptables -F                 # delete all rules from all chains
iptables -X                 # delete all user chains (non built-in chains)

Block everything firewall

This blocks everything. You will only be able to access the machine from the console. Don't do this if you are working remotely because your connection will instantly be dropped. Another way to do this would be to disable the network interface. The advantage of blocking everything with iptables instead of shutting down a network interface is that this leaves the kernel network layer still running. Applications will not complain about the network being unavailable. This also blocks all network interfaces at once, so if you have a machine with multiple interfaces this will take care of them all.

#!/bin/sh
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -F
iptables -X
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

Allow everything firewall

This opens up everything. It's the exact opposite of Block everything. The firewall is still technically running, but every packet is allowed through. This is the safe way to open the firewall without accidentally locking yourself out.

#!/bin/sh
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -F
iptables -X

Minimal emergency firewall

I use this to shut down everything except SSH port 22. This is my panic script. If something seems suspicious then I use this script to put a machine into as safe a state as possible while still allowing remote SSH connections.

Note that a machine with these rules won't be visible on the network with ping. Nmap by default does a ping test before mapping a machine. If you want to scan it with nmap you will have to use "nmap -P0" to scan without first checking ping.

#!/bin/sh
# Minimal emergency firewall (block everything except SSH).
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -F
iptables -X
iptables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
iptables -P INPUT DROP
iptables -A OUTPUT -p tcp -m tcp --sport 22 -j ACCEPT
iptables -P OUTPUT DROP

A practical, simple iptables firewall init.d script

For my real firewall I use an init.d script to store the configuration and to load the rules when the system boots. RedHat has a similar mechanism setup by default. Oddly, Ubuntu has no standard for restoring iptables rules on boot which is why I wrote this script to begin with. It turned out that I liked storing the rules this way better than I liked the RedHat style anyway.

To restore rules on boot, copy this script to /etc/init.d/firewall. On Ubuntu or Debian systems, run "update-rc.d firewall defaults" and the system will from then on start loading the firewall rules on boot. On RedHat systems, run "chkconfig --add firewall" and the system will run the script on boot.

This script includes options to start, stop, and show the status of iptables. The "stop" command doesn't really stop iptables (it is not a daemon). In this case, "stop" just flushes all policies and rules which opens networking to all traffic.

Click here to download: firewall <include src="http://www.noah.org/engineering/src/shell/firewall" highlight="sh" />

Funny story

At one time I had an iptables rule on all my machines that limited pings to 1 per second. By default the ping command sends 1 ICMP packet per second. Everything was fine and eventually I forgot about the rule. Months later I noticed that mtr was reporting high packet loss to a machine. A co-worker helped me investigate and the packet loss only got worse. Then the machine would intermittently stop accepting new SSH connections. All outside connections go through a load balancer. The load balancer is setup to probe each cluster and if a machine does not respond to a ping every 10 minutes then the load balancer removes that machine from rotation (even if there is only one machine in a cluster). So as we tried to debug our packet loss with ping and mtr it would cause iptables to block ICMP and if the load balancer happened to be doing a probe then it would take the machine off the network. We thought things were really bad because we couldn't even connect to the server through through the load balancer interface. Huge packet loss and dropped SSH connections -- we were thinking to check for bad cables, bad switch, or a bad load balancer. Then we checked the load balancer logs and saw that it had removed the machine because of failed ping probes. Eventually I tried shutting off iptables and the problem went away. Finally we decided to look at the iptables rules which revealed the rule that was causing all the grief. This will cause apparent packet loss if two engineers both ping at the same time:

iptables -A INPUT -p icmp --icmp-type 8 -m limit --limit 1/second -j ACCEPT

Load firewall on boot

When you shutdown your server all the iptables rules will be lost. You need to run a firewall script every time you boot. Some people use firestarter, but I prefer edit my own simple init script.

RedHat

For RedHat you need to edit:

/etc/sysconfig/iptables

Don't confuse this with /etc/sysconfig/iptables-config. Also note that RedHat has a tool called system-security-level that overwrites /etc/sysconfig/iptables, so if you run system-security-level you will loose your changes. You can edit the file manually or you can use system-security-level. Choose one or the other, not both.

You can also setup the firewall the way you want using the iptables command and then save the settings using RedHat's inti.d script:

/etc/init.d/iptables save

Ubuntu/Debian

For Ubuntu/Debian you can put an init script into /etc/init.d then link to an 'S' file in /etc/rc2.d

cp firewall /etc/init.d/firewall
chmod 755 /etc/init.d/firewall
cd /etc/rc2.d/
ln -s ../init.d/firewall S99firewall

Traffic shaping

Most iptables installs come with the "TOS" module (Type Of Service):

iptables -m tos -h

The TOS module lets you flag packets for different processing based on the IP packet header's TOS (now called Differentiated Services Code Point -- DSCP). IP packet headers contain an 8 bit field called DSCP (previously TOS) which can be used by the user application to indicate the priority of traffic. OpenSSH marks its packets depending on whether they originate from `ssh` or `scp`. The `ssh` packets are marked as "low delay" which denotes interactive traffic whereas `scp` packets are marked as "throughput" which denotes bulk traffic that is not sensitive to delays or latency.

Iptables also has a "DSCP" module. It's not clear which one to use for traffic shaping of SSH traffic. It seems that OpenSSH is still using the old TOS values, so it may be that the "TOS" module is the better choice at the moment.

This is a complex topic. I need to expand this with a simple setup that shows how to boost priority of interactive applications like SSH and possibly HTTP, while lowering priority for everything else. | Gentoo Wiki is one of the better documentation sources I have found.

TCNG seems interesting. I have yet to try it:

http://tcng.sourceforge.net/

I tried this without much luck:

http://lartc.org/howto/lartc.cookbook.ultimate-tc.html#AEN2210

This page also has some notes: http://www.void.gr/kargig/blog/2005/07/27/traffic-shaping-a-dsl-line-with-linux/

Handy commands

Ban -- block an annoying machine

This blocks a specific IP address from reaching your server. This is useful if you are getting annoying traffic from another machine and you want to get rid of them. Replace 255.255.255.255 with the IP address you want to drop.

iptables -I INPUT -j DROP -s 255.255.255.255

I set these aliases in my .bash_aliases file (sourced by .bashrc):

alias ban='iptables -I INPUT -j DROP -s'
alias unban='iptables -D INPUT -j DROP -s'

A very useful tool to do this automatically is fail2ban.

Show packet and byte counts

This shows the counters for each rule in a chain. This shows the number of packets and bytes that have gone through a specific chain. You can use this to measure traffic.

iptables -L INPUT -v