A basic firewall configuration suitable for a workstation
Introduction
We will create a basic packet-filtering firewall. The firewall will have the following properties:
- By default - i.e. unless we explicitly indicate otherwise - all ports will not respond to external connection attempts. Packets intended for all ports will be dropped, meaning that no indication will be given to the machine sending the packet whether the packet has been delivered or whether the connection attempt has been rejected.
- External connection attempts will be accepted for those connections which have been established from the local machine, or are related to those connections which have been established from the local machine.
- External connection attempts to the local SSH daemon on port 22 will be accepted.
Preparing the system
To create a basic firewall you'll need to ensure that your kernel has support compiled in for Network Packet Filtering. In addition, the following components will need to be compiled into the kernel or compiled as modules: ip_tables, ip_conntrack, iptable_filter, and ipt_state. These provide system functions that will be used by this firewall configuration.
If you choose to compile these as modules, you will need to ensure that they will be loaded into the kernel before configuration of this basic firewall is attempted. This can be done either by adding them, one per line, to /etc/modules, or by loading them using the modprobe command in the firewall configuration script. (Debian users, use the modconf utility.)
The firewall configuration script
#!/bin/sh set -e iptables="/sbin/iptables" modprobe="/sbin/modprobe" load () { echo "Loading kernel modules..." $modprobe ip_tables $modprobe ip_conntrack $modprobe iptable_filter $modprobe ipt_state echo "Kernel modules loaded." echo "Loading rules..." $iptables -P FORWARD DROP $iptables -P INPUT DROP $iptables -A INPUT -p tcp -m tcp --destination-port 22 -j ACCEPT $iptables -A INPUT -p ALL -m state --state ESTABLISHED,RELATED -j ACCEPT $iptables -A INPUT -s 127.0.0.1 -j ACCEPT echo "Rules loaded." } flush () { echo "Flushing rules..." $iptables -P FORWARD ACCEPT $iptables -F INPUT $iptables -P INPUT ACCEPT echo "Rules flushed." } case "$1" in start|restart) flush load ;; stop) flush ;; *) echo "usage: start|stop|restart." ;; esac exit 0
Explanation
$modprobe ip_tables
$modprobe ip_contrack
$modprobe iptable_filter
$modprobe ipt_state
- If these modules are compiled into the kernel, or are already loaded through /etc/modules then these lines may be commented out.
$iptables -P FORWARD DROP
$iptables -P INPUT DROP
- The default action (-P) to be taken for any packet not intended for this network device - i.e. intended to be forwared (FORWARD) - and for any packet intended as input to the local machine (INPUT), is to drop it (DROP). The default action specifies the action that will be performed on the packet if we do not explicitly indicate some other action.
$iptables -A INPUT -p tcp -m tcp --destination-port 22 -j ACCEPT
- Rules are checked sequentially. We append (-A) the first rule for any packet intended for the local machine (INPUT). Here we explicitly state that for any packet intended as input for the local machine, if the packet uses the tcp protocol (-p tcp), then we specify the tcp module (-m tcp) (needed by the --destination-port match), and if the destination port of the packet is 22 (--destination-port 22), then we jump (-j) this packet to be accepted (ACCEPT).
$iptables -A INPUT -p ALL -m state --state ESTABLISHED,RELATED -j ACCEPT
- We append (-A) the second rule for any packet intended for the local machine (INPUT). Here we explicitly state that for any packet intended for the local machine (INPUT), using any protocol (-p ALL), we load the state module (-m state), and if the state of the connection (--state) is established from the local machine (ESTABLISHED) or is related to a connection established from the local machine (RELATED), then we jump (-j) this packet to be accepted (ACCEPT).
$iptables -A INPUT -s 127.0.0.1 -j ACCEPT
- We append (-A) the third rule for any packet intended for the local machine (INPUT). Here we explicitly state that for any packet intended for the local machine (INPUT), originating from the source address (-s) of the local machine (127.0.0.1), we jump (-j) this packet to be accepted (ACCEPT).
We have only made explicit three acceptance conditions. A packet that does not match any acceptance condition will traverse our firewall in accordance with the default rule for packets of its destination type (here, INPUT or FORWARD). The default action (-P) we have specified for packets which do not meet any acceptance conditions is to be dropped (DROP).
Adding features
We have already allowed external connections to be made through our firewall to a SSH daemon listening on port 22 of the local machine. Suppose that we would also like to allow external connections for an FTP server which by default listens on port 21.
To also allow external connections to port 21, we modify the line:
$iptables -A INPUT -p tcp -m tcp --destination-port 22 -j ACCEPT
To read:
$iptables -A INPUT -p tcp -m tcp --destination-port 21:22 -j ACCEPT
Now external connections to port 21 (an FTP server on the local machine) will also be allowed through the firewall.
Usage
Save the firewall configuration script as a file and place it with the other system initialization scripts.
The file must be made executable so that it can be executed as a script.
To make the file executable, execute the command:
chmod a+x [filename]
This will make the file executable by all users, which is not a problem, because only users with permission to execute the modprobe and iptables commands will affect the firewall or system configuration.
The script may be executed by invoking in the directory of the script:
./[script] [start|restart|stop]
In order for the firewall to be started during system initialization, you will need to ensure it is incorporated into your system's init configuration.
For more information on how to install the script into your initscripts, see
this page