Archive for July, 2015

After the basics in part I, on to IPv6 and NAT. The title is misleading here: iptables exists for IPv6 and iptables can do NAT, but iptables cannot do NAT for IPv6 connections.

As for IPv6, this part is very simple: just add a ‘6’ between ‘ip’ and ‘tables’…


… and it will work for IPv6. As you can see above, since IPv6 addresses are longer, rules tend to split over two rows in a smaller console window.

NAT is an entirely different matter as it involves the translation of an IP address in the IP header of a packet. It doesn’t have much use for a standalone system, but if the Linux is used for routing it’s often needed.

I mentioned before iptables uses chains, but it also uses tables. The table that has been discussed so far is the ‘filter’ table. The ‘nat’ table takes care of NAT. Since it’s an entirely different table, it has its own set of chains:

  • PREROUTING, which applies NAT before the packet is routed or checked by the ‘filter’ table. It is most useful for destination NAT.
  • INPUT is not present in all recent versions anymore and does not serve any real purpose anymore.
  • OUTPUT is for packets originating from the local machine. In general they don’t need NAT s this is rarely used.
  • POSTROUTING applies NAT after the routing of the packet, if it hasn’t been filtered by the ‘filter’ table. It is most useful for source NAT.

A look at the current rule set can be done with iptables -L -v -t nat and rules can be added the same way as in the filter table, except that the parameter -t nat is added every time. The only difference is in the action to take for a rule that matches, the -j parameter.

For the ‘filter’ tables, possible target are ACCEPT and DROP, but for the ‘nat’ table this is different:

  • DNAT specifies destination NAT. It must be followed by –to-destination and the destination. The destination can be an IP address, but if a port was specified in the rule it can also be a socket, e.g. This makes port translations possible. A typical use case is if you want to make a server inside your network with a private IP address reachable from the internet.
  • SNAT is source NAT, and typically used for static NAT translations for an inside host with a private IP address towards its public IP address. It must be followed by the –to parameter that defines an IP address. It can also define a pool of IP addresses (e.g. and a range of source ports.
  • MASQUERADE is a special case: it is a source NAT behind the outgoing interface’s IP address (hide-NAT). This is ideal for interfaces which use DHCP to receive a public IP address from a provider. No other parameters need to be specified, so it’s not required to change this rule every time the public IP address changes.

These targets by themselves do not block or allow a connection. It’s still required to define the connection in the main ‘filter’ table and allow it.

Examples for NAT:

  • Forward incoming SIP connections (control traffic and voice payload) towards an inside IP phone at Allow the control traffic only from one outside SIP server at The outside interface is eth1.
    iptables -t nat -A PREROUTING -i eth1 -p udp –dport 16384 -j DNAT –to-destination
    iptables -t nat -A PREROUTING -i eth1 -p udp –dport 5060 -j DNAT –to-destination
    iptables -A FORWARD -d -p udp –dport 16384 -j ACCEPT
    iptables -A FORWARD -s -d -p udp –dport 5060 -j ACCEPT
  • Use IP addres as outgoing IP address for SMTP traffic from server
    iptables -t nat -A POSTROUTING -s -p tcp –dport 25 -j SNAT –to
    iptables -A FORWARD -s -p tcp –dport 25 -j ACCEPT
  • Use the interface IP address for all other outgoing connections on interface eth1.
    iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE


Notice that for rules in the ‘filter’ table that correspond to a NAT rule in the PREROUTING table, the IP addresses are used that are seen after the NAT has taken place, and for the POSTROUTING it’s the original IP addresses that are used. This is because the following order, as mentioned earlier, is very important here.

This is the IPv6 and NAT part of iptables. Up next: optimization and hardening of the rule set.


Most modern Linux distributions come with a firewall package already active. Since it’s often set in an ‘allow-all’ mode, people are often unaware of it.


Meet iptables, a basic yet powerful stateful firewall. You can see a default ‘allow-all’ policy above. Note that there are three different chains: INPUT, FORWARD and OUTPUT. Traffic can only match one of these three chains.

  • INPUT is for all traffic that is destined for the local Linux. It’s typically used to filter local services, e.g. you can allow only certain subnets to connect to the Linux via SSH, or shield off a port used by a process that you don’t want to be visible from the internet. This is also for response traffic from connections initiated locally.
  • FORWARD is for all traffic traversing the device. This requires routing functionality to be activated. On Debian-based Linux versions you can do this by adding or modifying the line net.ipv4.ip_forward=1 in /etc/sysctl.conf and perhaps adding some static routes.
  • OUTPUT is all traffic that originates from the local Linux. This is both for outbound connections as for response traffic for local services.

Looking at the current rule set can be done with iptables -L -v, where the optional -v parameter displays extra detail. Adding a rule can be done with iptables -A followed by the chain and the parameters of the rule. The most common ones are:

  • -p defines the protocol: udp, tcp, icmp or an IP Protocol number. You can modify the /etc/protocols file to make Linux recognize an IP Protocol number by name.
  • -i is the incoming interface. This is not supported in the OUTPUT chain for obvious reasons.
  • -o is the outgoing interface. This is not supported in the INPUT chain.
  • -s is the source subnet or host.
  • -d is the destination subnet or host.
  • – -dport (without the space) is the destination port, only valid if the protocol is defined as TCP or UDP. This can be a single port or a range, separated by a double colon.
  • – -sport (without the space) is the source port, or range of ports.
  • -j is the action to take. For the purposes of this article, let’s assume only ACCEPT and DROP are possible. More options will be discussed in upcoming blog posts.

The parameters not defined in a rule are assumed to have the value ‘any’. Examples:

  • Add a rule to allow SSH to the local Linux from one single host
    iptables -A INPUT -p tcp -s –dport 22 -j ACCEPT
  • Allowing subnet to do Remote Desktop to server
    iptables -A FORWARD -p tcp -s -dport 3389 -j ACCEPT
  • Block any traffic through the device towards UDP ports 10000 to 11000, regardless of source and destination:
    iptables -A FORWARD -p udp –dport 10000:11000 -j DROP
  • Don’t allow any traffic from interface eth4 to interface eth6:
    iptables -A FORWARD -i eth4 -o eth6 -j DROP

There is one additional rule which you will likely need in the configuration, but which differs from the rest of the rules: the stateful traffic rule. Although iptables by default keeps a state tables, it does not use it for traffic matching unless you tell it to. The rules to do this:

iptables -A INPUT -m conntrack –ctstate ESTABLISHED -j ACCEPT
iptables -A FORWARD -m conntrack –ctstate ESTABLISHED -j ACCEPT
iptables -A OUTPUT -m conntrack –ctstate ESTABLISHED -j ACCEPT

This calls in the module for connection tracking (-m conntrack) and matches any connections which have been seen before (ESTABLISHED). It is best to add this rule first this to avoid any drop rules from dropping traffic from known connections.

To modify the default policy, use the -P switch. For example, to block all local incoming connections by default:

iptables -P INPUT DROP

WARNING: When configuring iptables for the first time, especially via SSH, you have to be careful not to lock yourself out of the system. On top of that, some processes use IP communication using the loopback IP address internally. If you tell iptables to block this, it may break some applications!

Review what you want to achieve. For example, say you want to change the default iptables policy to drop any incoming connections, except http traffic and ssh from your computer:

  1. First add the rules allowing internal and stateful traffic:
    iptables -A INPUT -m conntrack –ctstate ESTABLISHED -j ACCEPT
    iptables -A INPUT -i lo -j ACCEPT
  2. Then add the rules allowing the connections:
    iptables -A INPUT -p tcp –dport 80 -j ACCEPT
    iptables -A INPUT -p tcp -s –dport 22 -j ACCEPT
  3. Finally set the policy to deny by default:
    iptables -P INPUT DROP


The OUTPUT chain can stay with a default allow action. If you modify it as well, be sure to add the rules for internal and stateful traffic again.

You can check the state table live via cat /proc/net/ip_conntrack


Here you see an example of one SSH connection and a NTP connection in the state table.

These are the iptables basics. In upcoming blog posts, I’ll talk about NAT, IPv6, optimization, hardening iptables security and increasing the scalability for large rule sets.