FIREWALL: iptables: Mini howto (en)
iptables is a firewall, which is by default installed in almost all Linux distributions, such as Ubuntu, Kubuntu, Xubuntu, Fedora Core, etc. When we install Ubuntu, iptables is already installed, but by default, it allows all traffic to pass through.
Indeed, there are many and can become very complex configuration techniques for iptables. On this occasion, we will only try to perform a simple firewall / iptables configuration.
Basic Commands
You can write,
$ sudo iptables -L
This will display the existing "rules" in iptables. If we have just installed a server, usually there are no rules installed yet, we will see
Chain INPUT (policy ACCEPT) target prot opt source destination
Chain FORWARD (policy ACCEPT) target prot opt source destination
Chain OUTPUT (policy ACCEPT) target prot opt source destination
Basic iptables Options
Here are some basic options commonly used in configuring iptables.
-A – Add this rule to an existing chain of rules. Valid chains are INPUT, FORWARD, and OUTPUT. We usually use the INPUT chain, which impacts incoming traffic.
-L – Displays the list of existing rules in iptables.
-m state – Allows rules to be matched based on connection state. Enables the use of the -–state option.
--state – Defines a list of states for the rule to match. Some valid states are,
NEW – A new connection that has not been seen before. RELATED – A new connection, but related to another allowed connection. ESTABLISHED – A connection that has already been made. INVALID – Traffic that cannot be identified for various reasons.
-m limit - Required by a rule if it wants to match within a certain time/number. Allows the use of the --limit option. Useful for limiting logging rules.
--limit – The maximum matching rate, given in the form of a number followed by "/second", "/minute", "/hour", or "/day" depending on how often we want to match the rule. If this option is not used, the default is "3/hour".
-p – The protocol used for the connection.
--dport – The destination port used by the iptables rule. It can be a single port, or a range written as start:end, which will match all ports from start to end.
-j - Jump to a specific target. iptables has four (4) default targets,
ACCEPT - Accept the packet and stop processing rules in this chain. REJECT - Reject the packet and notify the sender that we are rejecting it, and stop processing rules in this chain. DROP – Silently ignore the packet, and stop processing rules in this chain. LOG - Log the packet, and continue processing rules in this chain. Allows the use of the --log-prefix and --log-level options.
--log-prefix – If logging is done, place text/writing before the record. Use quotes around the text/writing.
--log-level – Logs using the syslog level. 7 is a good choice, unless we need something else.
-i – Match if the incoming packet is from a certain interface.
-I – Insert a rule. Requires two (2) options, namely, which rule chain and the rule number. So -I INPUT 5 would insert into the INPUT chain and make it rule number 5 on the list.
-v – Displays more information on the screen. Very helpful if there are several rules that look similar when displayed without -v.
Allowing Established Connection Sessions
We can allow sessions of established connections to receive traffic, through the command,
$ sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
Allow Incoming Traffic to Specific Ports.
At the beginning of the process, iptables should block all traffic. Usually, we need to work through an SSH channel, so we typically allow SSH traffic and block other traffic.
To allow incoming traffic to the default SSH port number 22, we must allow all incoming TCP traffic to port 22.
$ sudo iptables -A INPUT -p tcp --dport ssh -j ACCEPT
From the list of options above, we know that the iptables rule is set to
insert this rule into the input chain (-A INPUT) meaning we are looking at incoming traffic. check if the protocol used is TCP (-p tcp). If TCP, check if the packet is going to the SSH port (--dport ssh). If going to SSH, then the packet is accepted (-j ACCEPT).
Let's check the rule formed by the command above using the iptables -L command,
$ sudo iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
Next, we will allow all web traffic to enter, use the following command
$ sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
Check the rule we created using the iptables -L command, as follows,
$ sudo iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED ACCEPT tcp -- anywhere anywhere tcp dpt:ssh ACCEPT tcp -- anywhere anywhere tcp dpt:www
We must specifically allow TCP traffic to SSH and Web ports, but we have not blocked anything, and all incoming traffic can enter.
Blocking Traffic
If a rule has decided to accept a packet (ACCEPT), then the next rule will not affect that packet. Since the rules we created allow SSH and Web traffic, as long as the rule to block all traffic is placed last after the rules allowing SSH and Web, we will still be able to receive the SSH and Web traffic we want. So we must add (-A) a rule to block traffic at the end.
$ sudo iptables -A INPUT -j DROP $ sudo iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED ACCEPT tcp -- anywhere anywhere tcp dpt:ssh ACCEPT tcp -- anywhere anywhere tcp dpt:www DROP all -- anywhere anywhere
Since we do not specify an interface or protocol used, all traffic to all ports and all interfaces will be blocked, except for web and SSH.
Editing iptables
The main problem we will encounter is that the loopback port on the "lo" interface will be blocked. Therefore, we need to allow all traffic for the loopback ("lo"). This can be done by Inserting (-I) a rule in the INPUT chain for the lo interface, so it is placed at the very top.
$ sudo iptables -I INPUT 1 -i lo -j ACCEPT $ sudo iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- anywhere anywhere ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED ACCEPT tcp -- anywhere anywhere tcp dpt:ssh ACCEPT tcp -- anywhere anywhere tcp dpt:www DROP all -- anywhere anywhere
If we look above, the top rule and the bottom rule are somewhat similar, to see more details of these rules, we can use the command,
$ sudo iptables -L -v
Chain INPUT (policy ALLOW 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT all -- lo any anywhere anywhere 0 0 ACCEPT all -- any any anywhere anywhere state RELATED,ESTABLISHED 0 0 ACCEPT tcp -- any any anywhere anywhere tcp dpt:ssh 0 0 ACCEPT tcp -- any any anywhere anywhere tcp dpt:www 0 0 DROP all -- any any anywhere anywhere
We see more information here. The rule to allow loopback is very important, as many programs will use the loopback interface to communicate with each other. If loopback is not allowed, then we will likely damage those programs.
Logging / Recording
In all the examples above, all traffic is not logged. If we want to record packets that are dropped, the quickest way is,
$ sudo iptables -I INPUT 5 -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
Please look at the top to see what happens in the logging process.
Saving iptables
If we reboot the machine we are using, then what we have done so far will be lost. Of course, we could retype all the commands we entered one by one every time we reboot, to make our lives easier, then we can use the iptables-save and iptables-restore commands to save and restore iptables.
For those of you who use Ubuntu, especially Ubuntu Fiesty, it seems that Ubuntu Network Manager (still beta) is somewhat in conflict with iptables. Therefore, it might be a good idea to bypass the Ubuntu Network Manager.
By not using Ubuntu Network Manager, we can save the iptables configuration to be started every time we boot using the command
$ sudo sh -c "iptables-save > /etc/iptables.rules"
We need to modify /etc/network/interfaces so that the iptables rules we use can run automatically. Indeed, we need to know which interface the rules we create will be used on. Typically, we use eth0. For wireless interfaces, we can check their use with the command,
$ iwconfig
We need to edit the /etc/network/interfaces file using the command
$ sudo nano /etc/network/interfaces
If we have found the name of the interface being used, then at the end of the interface we can add the command,
pre-up iptables-restore < /etc/iptables.rules
Next, we add the command after the interface is down, using the command,
post-down iptables-restore < /etc/iptables.rules
A real example of the interfaces configuration is as follows,
auto eth0 iface eth0 inet dhcp pre-up iptables-restore < /etc/iptables.rules post-down iptables-restore < /etc/iptables.rules
Startup Configuration in NetworkManager
Ubuntu Network Manager has the ability to run scripts when it activates or deactivates an interface. To save iptables rules at shutdown, and restore iptables at startup, we will create such a script. To start, we can edit the file,
$ gksudo gedit /etc/NetworkManager/dispatcher.d/01firewall
We can enter the script below through the editor, save and exit.
#!/bin/bash
if [ -x /usr/bin/logger ]; then LOGGER="/usr/bin/logger -s -p daemon.info -t FirewallHandler" else LOGGER=echo fi case "$2" in pre-up) if [ ! -r /etc/iptables.rules ]; then ${LOGGER} "No iptables rules exist to restore." return fi if [ ! -x /sbin/iptables-restore ]; then ${LOGGER} "No program exists to restore iptables rules." return fi ${LOGGER} "Restoring iptables rules" /sbin/iptables-restore -c < /etc/iptables.rules ;; post-down) if [ ! -x /sbin/iptables-save ]; then ${LOGGER} "No program exists to save iptables rules." return fi ${LOGGER} "Saving iptables rules." /sbin/iptables-save -c > /etc/iptables.rules ;; *) ;; esac
Finally, we need to ensure that Ubuntu Network Manager can run this script. Through the console, we can run the following command,
$ sudo chmod +x /etc/NetworkManager/dispatcher.d/01firewall
A Little Tip
If we often manually edit iptables. Frequent iptables changes usually occur during the development phase, during operational times there are actually not many changes to iptables rules. If there are quite a lot of changes, then we should add the following sentences to the /etc/network/interfaces file:
pre-up iptables-restore < /etc/iptables.rules post-down iptables-save > /etc/iptables.rules
The sentence "post-down iptables-save > /etc/iptables.rules" will save the rules so they can be used again after booting.
Using iptables-save/restore for Rule Testing
If we are experimenting with iptables, it is advisable to use the iptables-save and iptables-restore commands to edit and test the rules we create. To edit the iptables rules we create we can use the following command (for example using gedit),
$ sudo iptables-save > /etc/iptables.rules $ gksudo gedit /etc/iptables.rules
We will obtain a file similar to what we did,
# Generated by iptables-save v1.3.1 on Sun Apr 23 06:19:53 2006 *filter :INPUT ACCEPT [368:102354] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [92952:20764374] -A INPUT -i lo -j ACCEPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -i eth0 -p tcp -m tcp --dport 22 -j ACCEPT -A INPUT -i eth0 -p tcp -m tcp --dport 80 -j ACCEPT -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7 -A INPUT -j DROP COMMIT # Completed on Sun Apr 23 06:19:53 2006
It appears from the file that these commands are iptables commands, without "iptables" itself. We can edit this file, and save it when finished. For testing it can be run using the command,
$ sudo iptables-restore < /etc/iptables.rules
After the test, we can save what is being tinkered with using the iptables-save command to the /etc/network/interfaces file through the command
$ sudo iptables-save > /etc/iptables.rules
More Detail About Logging
To see more details from the syslog we need to add an additional chain. Here is an example from /etc/iptables.rules showing how the iptables setup logs from syslog:
# Generated by iptables-save v1.3.1 on Sun Apr 23 05:32:09 2006 *filter :INPUT ACCEPT [273:55355] :FORWARD ACCEPT [0:0] :LOGNDROP - [0:0] :OUTPUT ACCEPT [92376:20668252] -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -i eth0 -p tcp -m tcp --dport 22 -j ACCEPT -A INPUT -i eth0 -p tcp -m tcp --dport 80 -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -j LOGNDROP -A LOGNDROP -p tcp -m limit --limit 5/min -j LOG --log-prefix "Denied TCP: " --log-level 7 -A LOGNDROP -p udp -m limit --limit 5/min -j LOG --log-prefix "Denied UDP: " --log-level 7 -A LOGNDROP -p icmp -m limit --limit 5/min -j LOG --log-prefix "Denied ICMP: " --log-level 7 -A LOGNDROP -j DROP COMMIT # Completed on Sun Apr 23 05:32:09 2006
Notice there is a new CHAIN called LOGNDROP at the beginning of the file. The standard DROP that is usually at the bottom of the INPUT chain is now replaced by LOGNDROP and adds protocol descriptions to make the logs easier to read. Finally, we will discard/drop traffic at the end of the LOGNDROP chain. Some notes below will provide an explanation of what happens,
--limit regulates how much logging from a rule to syslog --log-prefix "Denied..." adds a prefix to make reading the syslog easier --log-level 7 sets the level of information detail in the syslog
Disabling the Firewall
If we need to temporarily disable/turn off the firewall, this can be done easily using the flush (-F) command, as follows,
$ sudo iptables -F
Ease of Configuration Using Graphics
For those of us who find it difficult to use the console, we will be greatly assisted by various applications to configure the firewall using graphics. One of the favorite software that might be very helpful is,
Webmin - http://www.webmin.com Firestarter - http://www.fs-security.com