O'Reilly Hacks
oreilly.comO'Reilly NetworkSafari BookshelfConferences Sign In/My Account | View Cart   
Book List Learning Lab PDFs O'Reilly Gear Newsletters Press Room Jobs  

Buy the book!
Linux Server Hacks
By Rob Flickenger
January 2003
More Info

Creating a Firewall from the Command Line of any Server
You don't have to have a dedicated firewall to benefit from using iptables
[Discuss (2) | Link to this hack]

The netfilter firewall (available in Linux 2.4 and later) allows for very flexible firewall manipulation from the command line. Using iptables can take a while to get used to, but it allows for a very expressive syntax that lets you create complex (and hopefully useful ;) firewall rules.

Even if your machine isn't a "real" firewall (that is, it only has one network interface and isn't protecting other machines) the filter functionality can be very useful. Suppose you want to allow telnet access to this machine (just in case something happens to ssh or its libraries) but don't want to permit it from just anywhere on the Net. You could use a tcpwrapper (by populating /etc/hosts.allow and /etc/hosts.deny, and setting up /etc/inetd.conf appropriately). Or, you could use iptables with a line like this:

iptables -A INPUT -t filter -s ! -p tcp --dport 23 -j DROP

Generally, most people want to permit unrestricted access from trusted hosts, block all access from known problem hosts, and allow something in between for everyone else. Here is one method for using a whitelist, blacklist, and restricted port policy simultaneously.

# A simple firewall initialization script
ALLOWED="22 25 80 443"

# Drop all existing filter rules
iptables -F

# First, run through $WHITELIST, accepting all traffic from the hosts and networks
# contained therein.
for x in `grep -v ^# $WHITELIST | awk '{print $1}'`; do 
echo "Permitting $x..."
iptables -A INPUT -t filter -s $x -j ACCEPT

# Now run through $BLACKLIST, dropping all traffic from the hosts and networks
# contained therein.
for x in `grep -v ^# $BLACKLIST | awk '{print $1}'`; do 
echo "Blocking $x..."
iptables -A INPUT -t filter -s $x -j DROP

# Next, the permitted ports: What will we accept from hosts not appearing 
# on the blacklist?
for port in $ALLOWED; do 
echo "Accepting port $port..."
iptables -A INPUT -t filter -p tcp --dport $port -j ACCEPT

# Finally, unless it's mentioned above, and it's an inbound startup request,
# just drop it.
iptables -A INPUT -t filter -p tcp --syn -j DROP

Be sure to specify all of the ports you'd like to include in the $ALLOWED variable at the top of the script. If you forget to include 22, you won't be able to ssh into the box!

The /usr/local/etc/blacklist.txt file is populated with IP addresses, host names, and networks like this: # Portscanned on 8/15/02 # Who knows what evil lurks therein
r00tb0y.script-kiddie.coop # $0 s0rR33 u 31337 h4x0r!

Likewise, /usr/local/etc/whitelist.txt contains the "good guys" that should be permitted no matter what the other rules specify: # My workstation # the local network

Since we're only grabbing lines that don't start with #, you can comment out an entire line if you need to. The next time you run the script, any commented entries will be ignored. We run an iptables -F at the beginning to flush all existing filter entries, so you can simply run the script again when you make changes to blacklist.txt, whitelist.txt, or the ports specified in $ALLOWED.

Also note that this script only allows for TCP connections. If you need to also support UDP, ICMP, or some other protocol, run another pass just like the $ALLOWED for loop, but include your additional ports and protocols (passing -p udp or -p icmp to iptables, for example).

Be careful about using whitelists. Any IPs or networks appearing on this list will be permitted to access all ports on your machine. In some circumstances, a clever miscreant may be able to send forged packets apparently originating from one of those IPs, if they can find out ahead of time (or logically deduce) what IPs appear on your whitelist. This kind of attack is difficult to perform, but it is possible. If you are particularly paranoid, you might only allow whitelist addresses from networks that aren't routable over the Internet but are used on your internal network.

It is extremely useful to have console access while working with new firewall rules (you can't lock yourself out of the console with iptables!) If you get confused about where you are when working with iptables, remember that you can always list out all rules with iptables -L, and start over by issuing iptables -F. If iptables -L seems to hang, try iptables -L -n to show the rules without doing any DNS resolution -- your rules might accidentally be prohibiting DNS requests.

You can do a lot with simple filtering, but there's much more to iptables than just the filter target.

See also:

O'Reilly Home | Privacy Policy

© 2007 O'Reilly Media, Inc.
Website: | Customer Service: | Book issues:

All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.