iptables
Contents |
Basic iptables HOWTO
In this HOWTO I will show you how to create a very simple but effective iptables ruleset. The goal is to deny all incoming traffic besides established or related connections and allow all traffic outbound. I only use three rules along with DROP policies for the INPUT and FORWARD chains, you can modify the rules/policies to your needs.
Assumptions
- you have a kernel with netfilter support.
- all needed modules are loaded.
- you have the iptables userspace programs installed.
The Rules
Simple Iptables Ruleset
Here is the basic ruleset we will be using, it is commented to make it a little clearer of what the individual rules do.
*filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] # Allows all loopback traffic and drops all traffic to 127/8 not coming from the loopback interface. -A INPUT -i lo -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT # Accepts all related/established inbound connections -A INPUT - -m state --state ESTABLISHED,RELATED -j ACCEPT # log iptables denied calls (can be viewed with the 'dmesg' command) -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7 COMMIT
Learning The Rules
So what does all this mean? Let's break it down a little.
- *filter - here is the default table which contains our three built in chains. all rules belong to a chain and since this is a basic HOWTO i won't go further than the three basic chains.
- INPUT - this is the chain that holds our rules for traffic intended for our system. our policy for the INPUT table is DROP. it tells iptables to drop all incoming traffic that does not match a rule in the INPUT chain. exceptions can be added with rules in the INPUT chain.
- FORWARD - this chain holds rules for traffic intended for another system. our policy here is also set to DROP all traffic not intended for our system. You may add exemptions with a rule in the FORWARD chain or change the chains policy.
- OUTPUT - this chain holds rules for traffic leaving our system. here our ACCEPT policy tells iptables to allow all traffic leaving our system. You may want to deny certain traffic by adding rules to the OUTPUT chain or set the chains policy to DROP or REJECT and allow only trusted traffic to leave the system with rules in the OUTPUT chain.
- # - everything here is just a comment and is ignored by iptables, it is just a brief explanation of what each rule does.
- -A INPUT -i lo -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT - allows all traffic to the loopback network coming from the loopback device.
- -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT - allows all incoming established and related traffic.
- -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7 - log inbound traffic that occurs at least five times in one minute and log to syslog with "iptables denied:" prefix. "i wanted to keep this HOWTO simple but might add more on logging later."
- COMMIT - tells iptables this is the end of our rules file. don't forget this at the end of your rule file.
Dissecting A Rule
Here is our second rule. We know it ACCEPTS all traffic to loopback coming from loopback.
-A INPUT -i lo -s 127.0.0.0/8 -d 127.0.0.0/8 -j ALLOW
Let's break it down into pieces.
- -A - appends a rule to a chain. REMEMBER iptables rules are read in order from first to last.
- INPUT - the chain we are adding our rule to.
- -i - specifies the interface the traffic was received from. not applicable to the OUTPUT chain.
- lo - argument to the "-i" parameter.
- -s - specifies a source address. the ip/host of the source system.
- 127.0.0.0/8 - argument to the "-s" parameter. "this netblock is reserved for use by the loopback interface."
- -d - specifies a destination address. the ip/host of the destination system.
- 127.0.0.0/8 - argument to the "-d" parameter. "this netblock is reserved for use by the loopback interface."
- -j - specifies the target and tells iptables what to do if traffic matches the rule. this can be a user-defined chain or a built in target like DROP, ACCEPT, .., that decides the fate of the traffic immediately,
- ACCEPT - argument to the "-j" parameter. tells iptables to allow the traffic through.
Adding Rules
Using The Iptables Command
- the iptables command requires root privileges
To list all your current rules in all chains in iptables-save format:
$ iptables -S -P INPUT ACCEPT -P FORWARD ACCEPT -P OUTPUT ACCEPT
Let's add our rules.
$ iptables -A INPUT -i lo -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT $ iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
If you want logging add this one too, if not just skip it.
$ iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
Next we need to change the policy to "DROP" for the INPUT and FORWARD chains.
$ iptables -P INPUT DROP $ iptables -P FORWARD DROP
Now let's take another look at our rules in iptables-save format.
$ iptables -S -P INPUT DROP -P FORWARD DROP -P OUTPUT ACCEPT -A INPUT -s- 127.0.0.0/8 -d 127.0.0.0/8 -i lo -j ACCEPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7 (if you added log rule)
Save The rules. I like to save my rules as /etc/iptables.conf but it's not written in stone.
$ iptables-save > /etc/iptables.conf
- note - your rules will be lost on reboot. read the rest of this HOWTO for instructions on loading rules at boot or use the iptables-restore command.
Tighten up permissions
$ chmod 600 /etc/iptables.conf
Using A Text Editor
Open up your favorite text editor (I like vim myself) and add the rules just as shown here http://wiki.shellium.org/mediawiki/index.php?oldid=16925&rcid=17228#Simple_Iptables_Ruleset
Save the file. I like /etc/iptables.conf myself but once again not written in stone.
Load the rules from our newly created rules file
$ iptables-restore < /etc/iptables.conf
check that the rules were loaded successfully
$ iptables -S -P INPUT DROP -P FORWARD DROP -P OUTPUT ACCEPT -A INPUT -s 127.0.0.0/8 -d 127.0.0.0/8 -i lo -j ACCEPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7 (if you added log rule)
- note - your rules will be lost on reboot. read the rest of this HOWTO for instructions on loading rules at boot or use the iptables-restore command.
Tighten up permissions
$ chmod 600 /etc/iptables.conf
Loading Rules At Boot
- I am using Debian in these examples which does not provide an init script for iptables. If your distro provides one you may choose to use it instead.
Now we will create a script which ifup will run at boot. It is very simple and just runs iptables-restore to load our rule file.
$ echo '#!/bin/sh' > /etc/network/if-up.d/iptables $ echo "iptables-restore < /etc/iptables.conf" >> /etc/network/if-up.d/iptables $ chmod 700 /etc/network/if-up.d/iptables
Alternate Via Interfaces File
You can also have the rules loaded at boot via /etc/network/interfaces file like this:
iface eth0 inet dhcp
pre-up iptables-restore < /etc/iptables.conf
IPv6
You can firewall/filter ipv6 traffic the same way you do with ipv4 traffic, but for ipv6 traffic you wouldn't use iptables but ip6tables instead. I am not going to go into much detail about the differences between ipv4 and ipv6 but I will note that icmpv6 is used for a lot more than to see if a host is up. There are many documents online regarding IPv6 and ICMPv6 if you would like to know more.
Simple Ip6tables Ruleset
Let's take a look at our ipv6tables rules, there are a few minor differences between these rules and our iptables rules but they both do basically the same thing.
*filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] # Allows all loopback (lo) traffic and drops all traffic to ::1/128 that doesn't use lo -A INPUT -s ::1/128 -d ::1/128 -i lo -j ACCEPT # Accepts all established inbound connections -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # Allow ICMPv6 echo-request -A INPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT COMMIT
As you can see these rules look a lot like the rules we used earlier with iptables.
Learning The Rules
So what does all this mean? Let's break it down a little.
- *filter - here is the default table which contains our three built in chains. all rules belong to a chain and since this is a basic HOWTO i won't go further than the three basic chains.
- INPUT - this is the chain that holds our rules for traffic intended for our system. our policy for the INPUT table is DROP. it tells iptables to drop all incoming traffic that does not match a rule in the INPUT chain. exceptions can be adding with rules in the INPUT chain.
- FORWARD - this chain holds rules for traffic intended for another system. our policy here is also set to DROP all traffic not intended for our system. You may add exemptions with a rule in the FORWARD chain or change the chains policy.
- OUTPUT - this chain holds rules for traffic leaving our system. here our ACCEPT policy tells iptables to allow all traffic leaving our system. You may want to deny certain traffic by adding rules to the OUTPUT chain or set the chains policy to DROP or REJECT and allow only trusted traffic to leave the system with rules in the OUTPUT chain.
- # - everything here is just a comment and is ignored by iptables, it is just a brief explanation of what each rule/rules does.
- -A INPUT -s ::1/128 -d ::1/128 -i lo -j ACCEPT - allows all traffic to the loopback network coming from the loopback device.
- -A INPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT - allows all incoming icmpv6 echo-request's (ping)."to prevent DOS attacks the limit module (-m limit) may be used"
- -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT - allows all incoming established and related traffic.
- -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7 - log inbound traffic that occurs at least five times in one minute and log to syslog with "iptables denied:" prefix. "i wanted to keep this HOWTO simple but might add more on logging later."
- COMMIT - tells iptables this is the end of our rules file. don't forget this at the end of your rule file.
If you look at our iptables rules and these ip6tables rules you will notice only two differences:
- loopback address changed - we changed the looback address from 127.0.0.0/8 which is an ipv4 address to it's ipv6 address of ::1/128
- rule added - added rule "A INPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT" to allow the minimum of just an icmpv6 echo-request. "IPv6 uses icmp for a lot more than host discovery as mentioned earlier, at least allow the privilege of a ping unless you know what you are doing"
ICMPv6
To list available ICMPv6 types:
$ip6tables -p ipv6-icmp -h
You should get something similar to this:
Valid ICMPv6 Types: destination-unreachable no-route communication-prohibited address-unreachable port-unreachable packet-too-big time-exceeded (ttl-exceeded) ttl-zero-during-transit ttl-zero-during-reassembly parameter-problem bad-header unknown-header-type unknown-option echo-request (ping) echo-reply (pong) router-solicitation router-advertisement neighbour-solicitation (neighbor-solicitation) neighbour-advertisement (neighbor-advertisement) redirect
- I recommend allowing ICMPv6 echo-request at the very least