Defindit Docs and Howto Home

This page last modified: Dec 18 2006
keywords:iptables,security,ssh,ftp,http,ports,tcp,udp,routing,firewall,route,secure,network,nat,masquerade,linux,
description:Configuration examples for iptables firewall, including allowing connections, and building a router.
title:iptables configuration and examples for Fedora and Linux

Table of contents
-----------------

Introduction
Diagnosing iptables problems
Internal layout of the iptables file
Example one
Example two



Introduction
------------

Keep in mind that iptables is complex, and certain errors may allow
subtle attacks against your machine. My iptables files work, and some
of my iptables have been created in consultation with other system
administrators. My machines have successfully resisted all attacks,
but that could be luck as much as care and skill. Read available
iptables and security guides to verify that the advice and examples
given here are accurate. If you find a mistake, please use my contact
form to drop me a note.

http://laudeman.com/tom_mail.html


Other guides (of varying quality):

http://www.siliconvalleyccie.com/linux-hn/iptables-intro.htm
http://www.linuxguruz.com/iptables/

Before making changes, copy /etc/sysconfig/iptables to ~/ with a dated file name.
Just edit /etc/sysconfig/iptables
and restart with /etc/rc.d/init.d/iptables restart

iptables-save might be useful, but in general the iptables utilities
do not preserve comments. Reading an iptables file without comments is difficult.

Since you generally drop all connections not explicitly allowed, any
time your server offers a new service (like Postgres or MySQL)
iptables will need new rule. 



Diagnosing iptables problems
----------------------------

The most common diagnostic is to simply turn off iptables:

/etc/rc.d/init.d/iptables stop

You can use telnet to see if your machine is accepting connections on
a given port. To check ssh (port 22)

telnet example.com 22

If you get a response, then at least the daemon is running and able to
respond on that port. Of course, telnet won't be able to actually
carry on a meaningful dialog with the daemon. Ports are listed in
/etc/services.

You can check if a service is running with ps. To check if sshd is running:

ps aux | grep ssh

Ethernet and routing are other problems that are often associated with
iptables and firewalling. See my ethernet diagnostic how-to:

http://defindit.com/readme_files/netsetup.html

You can also use telnet to verify that connections are refused as a way to
verify that your firewall is keeping people out.

nc (aka netcat) is also handy for testing network connections.

nc -z example.com 80

[mst3k@zeus ~]$ nc -z example.com 80
Connection to example.com 80 port [tcp/http] succeeded!
[mst3k@zeus ~]$ nc -z localhost 80
Connection to localhost 80 port [tcp/http] succeeded!
[mst3k@zeus ~]$ nc -z localhost 8080
[mst3k@zeus ~]$

If you get no response, then the connection failed.



Internal layout of the iptables file
------------------------------------

The iptables file generally has one or more sections (two is the most
I've used). If you are doing nat or masquerading, you'll have two
sections. The first few lines of the filter section are fairly
standard, and pretty much static. The chain of rules (the actual "filters") is
kind of the body of the filter section and this is where you usually
make modifications. The end of the filter section is usually just a
command to drop any packet that didn't meet one of the filter
criteria.



Example one
-----------


# filter section.  I renamed my default chain from
# RH-Lokkit-0-50-INPUT or rh-input to "UVAfw", mostly to shorten
# it. The following lines seem more or less standard.



# Generated by iptables-save v1.2.1a on Fri Jun  1 14:04:15 2001
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [1531191:180073476]
:UVAfw - [0:0]


# Rules section.
# These rules are run in order. If a network packet is dropped by a
# rule, the packet is dropped and no more rules are run. If a packet
# passes one of the rules, the rules still run since a later rule may
# drop the packet (or deny the packet). I seem to recollect that REJECT
# sends back a nice message if the packet is refused. DROP silently
# drops the packet (e.g. connection) and nothing happens at the other
# end. In other words, if you DROP ssh and someone tries to ssh to your
# machine, their ssh client just sits waiting for a connection. The
# "attacker" isn't sure if your machine is slow, or the network
# connection is poor, or what. This is a good way to discourage attacks
# since they'll have to wait for a time out before being certain that
# your machine isn't accepting connections on the port in question.


# Always accept connections for lo which is your local loopback
# network connection, 127.0.0.1
-A INPUT -i lo -j ACCEPT

# Accept input from anything that passes your chain. My chain
# is called UVAfw, and you'll notice that all the following rules
# add (-A) things to this chain.
-A INPUT -j UVAfw


# Allow icmp (ping). 
# ping can be used as a DOS attack, so some people block it.
# Dropping ping packets can make diagnosing network problems more difficult.
-A UVAfw -s 128.143.0.0/16 -p ICMP -j ACCEPT

# Accept packets from related or established connections
# This is pretty standard. Accept incoming connections related to
# existing connections. Afaik, ftp and http both have a behavior where
# a connection is made on one port (80 for http) and the server
# creates another connection on another port.
-A UVAfw -m state --state RELATED,ESTABLISHED -j ACCEPT

# Allow postgres department X which for this example is the .19. subnet.
-A UVAfw -s 192.168.19.0/24  -p tcp -m tcp --dport 5432 -m state --state NEW -j ACCEPT

# Allow Postgres from a particular machine
-A UVAfw -s 192.168.16.125  -p tcp -m tcp --dport 5432 -m state --state NEW -j ACCEPT

# Allow rsync from any of the machines on the local network.
-A UVAfw -s 192.168.0.0/16 -p tcp -m tcp --dport 873 -m state --state NEW -j ACCEPT

# Allow ssh from everyone on the local network
-A UVAfw -s 192.168.0.0/16 -p tcp -m tcp --dport 22 -m state --state NEW -j ACCEPT

# Allow a particular machine (example.com) from outside to make an ssh connection
# In real life, this might be someone's home machine with a static ip address
-A UVAfw -s 192.0.34.166 -p tcp -m tcp --dport 22 -m state --state NEW -j ACCEPT

# Only allow netbios from the .19 subnet
-A UVAfw -s 192.168.19.0/24 -p tcp -m tcp --dport 137:139 -m state --state NEW -j ACCEPT

# Open up the 192.168 for vnc to my windows box
# This is a real example where I created a one machine 192.168 network
# in my office. The only machine on it was a Windows box running
# VNC. This allowed me to have Windows in a VNC window on my Linux
# machine. I suppose that I opened up all the tcp and udp ports since
# I'm not worried about being attacked by my own Windows box (but
# maybe I should be).
# It may be a mistake (or oversight) on my part that this is an INPUT
# rule instead of a UVAfw rule.
-A INPUT -s 192.168.0.0/16 -p tcp -m tcp -m state --state NEW -j ACCEPT
-A INPUT -s 192.168.0.0/16 -p udp -m state --state NEW -j ACCEPT

# Open samba access from the 192.168 to my windows box
# I'm not sure this worked in this form, but I think I had samba working.
-A UVAfw -s 192.168.0.0/16 -p udp --dport 137 -m state --state NEW -j ACCEPT
-A UVAfw -s 192.168.0.0/16 -p udp --dport 138 -m state --state NEW -j ACCEPT
-A UVAfw -s 192.168.0.0/16 -p tcp -m tcp --dport 139 -m state --state NEW -j ACCEPT
-A UVAfw -s 192.168.0.0/16 -p tcp -m tcp --dport 445 -m state --state NEW -j ACCEPT
-A UVAfw -p tcp -m tcp --dport 80 -m state --state NEW -j ACCEPT

# Open a port for Tomcat on 8080
# Allow connections from the local network, and from example.com
# The real life application would typically be alternate web servers
# on alternate ports. This is often done for testing a product, or
# testing a new version of the web server.
-A UVAfw -s 192.168.0.0/16 -p tcp -m tcp --dport 8080 -m state --state NEW -j ACCEPT
-A UVAfw -s 192.0.34.166 -p tcp -m tcp --dport 8080 -m state --state NEW -j ACCEPT

# Allow SSL https from anywhere.
-A UVAfw -p tcp -m tcp --dport 443 -m state --state NEW -j ACCEPT

# Accept cups printer connections from localhost
# In my real life iptables, these were commented out so they may not be quite correct.
-A UVAfw -s 127.0.0.1 -p tcp -m tcp --dport 631 -m state --state NEW -j ACCEPT
-A UVAfw -s 127.0.0.1 -p tcp -m tcp --dport 515 -m state --state NEW -j ACCEPT

# Log connections that don't come from UVA
# I can't remember what this was used for, which log file it went to,
# or how it appeared. 
-A UVAfw -s ! 128.143.0.0/16 -m limit --limit 25/hour -j LOG --log-prefix UVAfw_notlocal:


# Netatalk needs a flock of ports.
# This is the one-line-per-port example, and should work with
# older versions of iptables.
-A UVAfw -s 128.143.0.0/16 -p tcp --dport 427 -j ACCEPT
-A UVAfw -s 128.143.0.0/16 -p udp --dport 427 -j ACCEPT
-A UVAfw -s 128.143.0.0/16 -p tcp --dport 548 -j ACCEPT
-A UVAfw -s 128.143.0.0/16 -p tcp --dport 201 -j ACCEPT
-A UVAfw -s 128.143.0.0/16 -p tcp --dport 202 -j ACCEPT
-A UVAfw -s 128.143.0.0/16 -p tcp --dport 204 -j ACCEPT
-A UVAfw -s 128.143.0.0/16 -p tcp --dport 206 -j ACCEPT

#-A UVAfw -s 137.54.0.0/16 -p tcp --dport 427 -j ACCEPT
#-A UVAfw -s 137.54.0.0/16 -p udp --dport 427 -j ACCEPT
#-A UVAfw -s 137.54.0.0/16 -p tcp --dport 548 -j ACCEPT
#-A UVAfw -s 137.54.0.0/16 -p tcp --dport 201 -j ACCEPT
#-A UVAfw -s 137.54.0.0/16 -p tcp --dport 202 -j ACCEPT
#-A UVAfw -s 137.54.0.0/16 -p tcp --dport 204 -j ACCEPT
#-A UVAfw -s 137.54.0.0/16 -p tcp --dport 206 -j ACCEPT

# Multiport variant of the netatalk ports above.
# I'm not quite sure why 427 is missing.
-A UVAfw -m multiport -s 128.143.0.0/16 -p tcp --dports 548,201,202,204,206 -j ACCEPT


# Finally, if we get to this rule, drop the packet.
-A UVAfw -j DROP

# Always at the end. I guess this is a make-it-so type of command.
COMMIT



Example two
-----------


# These rules are for a machine with two ethernet ports. Originally,
# eth0 was the WAN (wide area network, the outside network). However, I
# think because I failed to associate each ethernet port with a hardware
# address, the ports switched during a reboot. This was very
# irritating. I haven't tested the hardware address fix, partly because
# this machine is rarely rebooted.
# 
# eth0 is the LAN (inside network, 10.10.1.x)
# eth1 is the WAN (outside network)
# 
# We'll assume that our hostname is example.com, and our ip address is
# 192.0.34.166.
# 
# A firewall router might look like this.

# This is the top section, and I think *nat means that this is
# related to nat (as opposed to packet filtering).
# These rules are all about routing and masquerading, and that there's
# a commit at the end of this section.


# Generated by iptables-save v1.2.8 on Sun Sep 14 21:03:10 2003
*nat
:PREROUTING ACCEPT [2634:169438]
:POSTROUTING ACCEPT [1:60]
:OUTPUT ACCEPT [45:2884]
# Masquerade (translate) everything on eth1 between the internal LAN
# and the outside world WAN.
-A POSTROUTING -o eth1 -j MASQUERADE
#
# SNAT is more powerful or something, but the masquerade seems to work fine.
# I'm not sure why I have both, but this setup is working.
# 
-A POSTROUTING -s 10.10.0.0/255.255.255.0 -o eth1 -j SNAT --to-source 216.12.18.87
COMMIT


# Below is the *filter section. This is all about what connections we
#  accept. There is a :FORWARD rule. I always use the same INPUT,
# FORWARD, and OUTPUT rules. Clearly they work, and I'm fairly certain
# they are required, but I'm not sure what they do.


# Completed on Sun Sep 14 21:03:10 2003
# Generated by iptables-save v1.2.8 on Sun Sep 14 21:03:10 2003
*filter
:INPUT ACCEPT [987:144395]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [45471:22115395]
:RH-Lokkit-0-50-INPUT - [0:0]


# Rules section. 


# Connection INPUT follows rule RH-Lokkit-0-50-INPUT
-A INPUT -j RH-Lokkit-0-50-INPUT

# Allow established connections on the WAN
-A INPUT -i eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT

# Allow all connections for the local, internal network.
-A INPUT -i eth0 -j ACCEPT

# Allow connection from 127.0.0.1 (the loopback interface) as usual.
-A INPUT -i lo -j ACCEPT


# Forward packets that are part of existing and
# related connections from eth0 to eth1.
# Things changed and eth0 is the LAN. I'm not sure how this interacts
# with the nat masquerading above.
# Note that somewhere (probably the network scripts) it is probable
# necessary to do the following:
# echo 1 > /proc/sys/net/ipv4/ip_forward
-A FORWARD -i eth0 -o eth1 -j ACCEPT


# This machine is a firewall, router, and server.
# Permit connections are part of existing and related connections.
-A FORWARD -i eth1 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT

# Allow connections from anyone on port 80
# The firewall also happens to be a web server.
-A RH-Lokkit-0-50-INPUT -p tcp -m tcp --dport 80 --tcp-flags SYN,RST,ACK SYN -j ACCEPT


# Allow http ssl, ftp, ssh, pop email, imap email, smtp mail delivery
-A RH-Lokkit-0-50-INPUT -p tcp -m tcp --dport 443 --tcp-flags SYN,RST,ACK SYN -j ACCEPT
-A RH-Lokkit-0-50-INPUT -p tcp -m tcp --dport 21 --tcp-flags SYN,RST,ACK SYN -j ACCEPT
-A RH-Lokkit-0-50-INPUT -p tcp -m tcp --dport 22 --tcp-flags SYN,RST,ACK SYN -j ACCEPT
-A RH-Lokkit-0-50-INPUT -p tcp -m tcp --dport 110 --tcp-flags SYN,RST,ACK SYN -j ACCEPT
-A RH-Lokkit-0-50-INPUT -p tcp -m tcp --dport 143 --tcp-flags SYN,RST,ACK SYN -j ACCEPT
-A RH-Lokkit-0-50-INPUT -p tcp -m tcp --dport 25 --tcp-flags SYN,RST,ACK SYN -j ACCEPT

# Hmmm. This seems superfluous
-A RH-Lokkit-0-50-INPUT -i lo -j ACCEPT

# Block a bunch of ports for services we don't use.
# This are probably not necessary since there are no daemons listening
# on these ports.
-A RH-Lokkit-0-50-INPUT -p tcp -m tcp --dport 0:1023 --tcp-flags SYN,RST,ACK SYN -j REJECT --reject-with icmp-port-unreachable
-A RH-Lokkit-0-50-INPUT -p tcp -m tcp --dport 2049 --tcp-flags SYN,RST,ACK SYN -j REJECT --reject-with icmp-port-unreachable
-A RH-Lokkit-0-50-INPUT -p udp -m udp --dport 0:1023 -j REJECT --reject-with icmp-port-unreachable
-A RH-Lokkit-0-50-INPUT -p udp -m udp --dport 2049 -j REJECT --reject-with icmp-port-unreachable
-A RH-Lokkit-0-50-INPUT -p tcp -m tcp --dport 6000:6009 --tcp-flags SYN,RST,ACK SYN -j REJECT --reject-with icmp-port-unreachable
-A RH-Lokkit-0-50-INPUT -p tcp -m tcp --dport 7100 --tcp-flags SYN,RST,ACK SYN -j REJECT --reject-with icmp-port-unreachable


# The final DROP rule is missing. Everything works fine, so I wonder
# if the DROP is necessary. It may well be that any packet not
# explicitly accepted is dropped.


# The usual final commit.
COMMIT
# Completed on Sun Sep 14 21:03:10 2003