Monday, May 17, 2010

Misc 23

IPTables was designed together with Netfilter. It is a replacement for the legacy IPChains. IPTables is compiled into the kernel and cannot be removed unless the kernel is recompiled.
IPTables is used primarily for filtering. There are two main paths a packet can take. Below is a simplified flowchart:

Notice that there is only two main paths a packet can take:
1) For packets destined FOR the machine, it would move through PREROUTING - INPUT - Program. Packets originating from the machine would move through Program - OUTPUT - POSTROUTING.
2) For packets destined THROUGH the machine, it would move through PREROUTING - FORWARD - POSTROUTING.

When a packet first enters the system, it would go into the PREROUTING chain. INPUT, OUPUT, FORWARD and POSTROUTING are also chains. For a packet to be successfully transmitted, it must be accepted in ALL chains. Therefore, for a packet to be forwarded through the system, it must be accepted by PREROUTING, FORWARD and POSTROUTING chains.

In each chain, there exists an implicit policy. The policy can either be ACCEPT or DENY. This is similar to the implicit deny entries at the bottom of every Cisco ACLs, except that you may change it to an implicit permit. If there is no match in all entries through the chain, the default policy is applied. This is an example on how to change INPUT's policy to ACCEPT and OUTPUT's policy to DROP:
iptables -P INPUT ACCEPT
iptables -P OUTPUT DROP

Now we'll begin to work through examples with this topology shown here:

In this topology, we have a Webserver in the inside network that runs both HTTP and HTTPS services. The Routing Server acts as the firewall between the Webserver and the hostile internet network. Here is the breakdown of the interfaces:
Routing Server - eth0 -
Routing Server - eth1 -
Webserver - eth0 -

Before we begin, we must load some modules into the kernel. To do this, we first generate .dep files for all modules. Type this as a privileged user:
depmod -a

Now that all modules are probed, we can enable the modules. We will be doing routing, PAT and Static NAT, so we'll enable these modules:
modprobe ip_tables
modprobe ip_conntrack
modprobe iptable_filter
modprobe iptable_mangle
modprobe iptable_nat
modprobe ipt_LOG
modprobe ipt_limit
modprobe ipt_state
modprobe ipt_MASQUERADE

Finally, we'll enable IPv4 routing by writing a "1" to the IP Forward process file like this:
echo "1" > /proc/sys/net/ipv4/ip_forward

Right now we can test connectivity by attempting to ping the internet interface of the Routing Server from the Webserver:

You should get replies at this point. If you don't, make sure that the Webserver has the correct default gateway set. However, pings will not work to the server because it does not know how to route back to At this point, we'll need to do some NATting.

Before we do anything, we'll set up the policies. It is best practice to set INPUT, OUTPUT and FORWARD to DROP by default. Then ACCEPT the protocols that you need. First we'll flush all chains of all entries, then set the policy to DROP:
iptables -F INPUT
iptables -F OUTPUT
iptables -F FORWARD
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

At this point your pings will no longer go through because there is nothing that ACCEPTs it. We'll create a new chain that permits ICMP. We first create the new chain with the -N parameter like this:
iptables -N ACCEPTICMP

Next we add the entry with the -A parameter, and specify that we ACCEPT ICMP as the transport protocol:
iptables -A ACCEPTICMP -p icmp -j ACCEPT

The -p specifies the transport protocol. Other options include tcp and udp. The -j option means JUMP. You can JUMP to an action (ACCEPT/DROP) or to another chain which I would demonstrate later. Right now we have a new chain named ACCEPTICMP that specifies to accept packets using ICMP transport.

Now we'll make another entry that permits HTTP and HTTPS traffic for both source and destination ports:
iptables -N ACCEPTWEB
iptables -A ACCEPTWEB -p tcp --sport 80 -j ACCEPT
iptables -A ACCEPTWEB -p tcp --dport 80 -j ACCEPT
iptables -A ACCEPTWEB -p tcp --sport 443 -j ACCEPT
iptables -A ACCEPTWEB -p tcp --dport 443 -j ACCEPT

To specify the source port (--sport) and destination port (--dport), you'll need to specify the protocol as well.

Now we'll insert the chain in INPUT, OUTPUT and FORWARD like this:
iptables -A INPUT -j ACCEPTWEB

In this way, instead of directly accepting the packet, it goes into the ACCEPTICMP chain. If there is no ACCEPT in ACCEPTICMP chain, it would then move on to the ACCEPTWEB chain. If there is still no ACCEPT matches, it uses the default policy.

Now you should be able to ping the internet interface of the Routing Server once again, but you're short of one more thing: PAT. To do PAT, you'll typically have to do it in the POSTROUTING chain. To enable PAT/NAT, you'll have to jump the packet to an action called "MASQUERADE". This is the typical implementation:
iptables -A POSTROUTING -t nat -o eth0 -j MASQUERADE

What the line says is that in the NAT table (-t nat) of the POSTROUTING chain, if the output interface (-o) is actually eth0, then masquerade (NAT) it. Recall that the output interface is eth0. The only time a packet is going out of eth0 is when a packet is destined for the internet, so the packet will only be masqueraded when it's destined for the outside.

Notice that I mentioned the NAT table of the POSTROUTING chain. What!? First there's chains, now there's tables!? It is actually part of a deeper concept which is omitted from the simplified diagram.

Now pinging and HTTP/HTTPS access should work as the outgoing packets will be translated into the interface IP of Routing Server's eth0 (

Now, notice that the inside server is actually a WEB server. This means that it must actually be accessible from outside for it to be of any use. In a Cisco router, this is done through a static NAT. In this case, we make use of the DNAT action. The DNAT action allows you to specify conditions for a packet's destination to be translated to a specified IP. In this case, anything reaching from eth0 with the destination port of 80 or 443 should have the destination translated to These two lines does this perfectly:
iptables -A PREROUTING -t nat -p tcp --dport 80 -i eth0 -j DNAT --to-destination
iptables -A PREROUTING -t nat -p tcp --dport 443 -i eth0 -j DNAT --to-destination

When you're done, use the command:
iptables-save > Save.ipt

The next time you want to run iptables, simply type:
iptables-restore Save.ipt

No comments :

Post a Comment