Designing a firewall using Iptables for the Home User

October 19, 2005
In the previous post on iptables , I had given an introduction about iptables - the firewall installed by default in all Linux distributions. Here I will explain how to go about designing a firewall keeping in mind the needs of a home user. I am assuming that the typical home user will be having a single computer connected to the internet via a cable, DSL, Dialup or ISDN connection. There is no hard and fast rule in designing a firewall. What is good for one situation may not be good for another. But you can arrive at a common ground on certain things.
Here I will explain how you can make your home machine which is connected to the internet , which I am giving the name 'my_machine', more secure. First let us see what are the services that are running on the home machine (my_machine). Usually when you install Linux on your machine, you will be having some default services.
They are as follows:
  • sshd - Secure Shell server
  • portmap - Which is used by file services like NFS
  • httpd - Apache web server
  • ftp server - File Transfer Protocol server. This is not usually running on a home machine but just make sure about it by checking. In RedHat, you can check by running the command:
    # chkconfig --list |grep ftp
    If you have nmap installed on your machine, you can run the command :
    # nmap -sS your_ip_address find all the open ports on your machine. The output for my_machine are as follows:

    Starting nmap 3.50 ( )
    at 2005-10-19 09:41 IST
    Interesting ports on my_ip_address:
    (The 1653 ports scanned but not shown below
    are in state: closed)
    22/tcp open ssh
    80/tcp open http
    111/tcp open rpcbind
    3306/tcp open mysql
    6000/tcp open X11
    32774/tcp open sometimes-rpc11

    Nmap run completed -- 1 IP address (1 host up)
    scanned in 1.205 seconds
    As seen above, I have apache webserver (http) , ssh, mysql server, X Server and rpcbind open to the outside world. rpcbind is used by NFS for mounting a remote drive. Usually a stand alone machine in our case my_machine need not open these services to the internet - except maybe ssh server which you might need to say - connect to your machine from a remote location - that too only if you have a static IP address, which is quite rare.
So lets get a pen and paper and decide how much or how little we want to open up our machine to the outside world. This is what I have decided:

  1. I want full access to my_machine locally. That is all the services should be available for the localhost or IP address .
  2. New connections originating from a remote machine to Portmap, ssh, webserver and X server has to be blocked.
  3. Established and related connections to my_machine has to be allowed. Here I would like to deviate from the topic to explain the terms 'new','established' and 'related'.For that you have to look at how TCP works. TCP is a connection-oriented protocol. Connection-oriented means that it makes sure all the packets reach the destination without any packet loss in transit. If a packet is lost, it re-sends the lost packet. This it achieves by using a set of flags. The flags are called SYN (Synchronize) and ACK (Acknowledge).
    When you click on a link in your web browser, your machine sends a SYN packet to the remote server which hosts the link. This process is called initiating a connection and is represented as NEW connection. When the remote server receives your request which has the flag SYN set, it sends a acknowledgment back to your machine by setting the SYN-ACK flag. And this is called a related connection.
    Once your machine receives the SYN-ACK packet, it responds with a final ACK packet which tells the remote machine that we have indeed received the packet. Then the connection is said to be established. This is called the three way handshake.
  4. Restrict anyone initiating a new connection to my_machine from a remote location.
  5. Allow all outgoing connections originating from my_machine.
  6. Restrict all other incoming connections.
Now that we have jotted down what we want to achieve, let us write rules for achieving it.

I usually write the rules in a script file and then execute the file. This allows me to keep everything organized. Also if I make a mistake, I just have to go back and edit the script and re-execute it. One other thing though - all allow rules must precede the deny rules.

Iptables Rules:

Allow localhost access to everything
iptables -A INPUT -s -j ACCEPT
iptables -A OUTPUT -s -j ACCEPT

Allow all related and established tcp connections to my_machine.
iptables -A INPUT -p tcp -m state


Allow all outgoing connections from my_machine.
iptables -A OUTPUT -j ACCEPT
... now start writing the deny rules.
Deny all new tcp connections from remote machines. And log the same.
iptables -A INPUT -p tcp -m state --state NEW -j LOG
iptables -A INPUT -p tcp -m state --state NEW -j DROP

Block the apache port on my_machine. See the nmap command listing above. Also log the traffic.
iptables -A INPUT -p tcp -s 0/0 --dport 80 -j LOG
iptables -A INPUT -p tcp -s 0/0 --dport 80 -j DROP
Note: LOG rule must precede the corresponding filter rule.

Block ssh to my_machine. Also log the traffic.
iptables -A INPUT -p tcp -s 0/0 --dport 22 -j LOG
iptables -A INPUT -p tcp -s 0/0 --dport 22 -j DROP

Finally Deny everything else.
iptables -A INPUT -j DROP
iptables -A FORWARD -j DROP
Now execute the script to load the rules into kernel space. That is it. Now we have got a robust firewall in place. You can check the results by re-running the nmap command listed above.


  • Great!
    I have never seen easier explanation

  • Why do you use a block all rule?
    Why not set the policy:

    iptables -P INPUT DROP

    You could make a rule to log in the end of the ruleset.