Networking

Use iptables to implement safe network address translation

This tutorial shows how to configure NAT using iptables on a Linux system.


Network address translation (NAT) has become a band-aid for the global shortage of IP addresses under IPv4. A permanent, proper solution, IPv6, is forthcoming; in the meantime, NAT will allow the Internet to grow while preventing us from running out of IP addresses.

Though many firewalls and routers support NAT, you may run into a situation where you need to use NAT, but your router doesn’t support it and you don’t have a firewall. When that happens, you can fire up a Linux server and use iptables. In this Daily Drill Down, I will explain how to easily set up Linux as a NAT-enabled router using iptables.

About my setup
For this article, I used two machines: a Red Hat Linux 7.2 server with two IP addresses assigned to its Ethernet 0 (eth0) interface (192.168.1.200 and 172.16.1.1) and a Windows 2000 Server with an IP address of 172.16.1.2. The gateway to the Internet is 192.168.1.1.

I will explain how to set up NAT (or IP masquerading, which is the outdated name for Linux NAT) using iptables on the Linux server and forward packets from the 172.16 network to the 192.168 network. Any traffic from the 172.16 network that goes on to the 192.168 network will appear to have originated from 192.168.1.200.

Using multiple addresses on the same interface
In most environments, you would use separate network interface cards (NICs) for each network, but if you don’t have one lying around, you can assign multiple addresses to the same network interface, as I have done in this example, and emulate two interfaces.

To add a second IP address to an interface, you need to create a subinterface for that NIC. On a Linux system, the IP address is assigned to a NIC via scripts that reside in the /etc/sysconfig/network-scripts directory. The name of the script that assigns attributes to the first Ethernet interface is named ifcfg-eth0 and has the following contents:
DEVICE=eth0
IPADDR=192.168.1.200
NETMASK=255.255.255.0
NETWORK=192.168.1.0
BROADCAST=192.168.1.255
ONBOOT=yes
BOOTPROTO=none


To assign a second IP address to this interface, you need to create a second file with the same name as the original, but with a subinterface designation of :0 at the end. For example, the name of the first subinterface-configuration file for ifcfg-eth0 is ifcfg-eth0:0 and the name of the subinterface is eth0:0. This file has the following sample contents:
DEVICE=eth0:0
IPADDR=172.16.1.1
NETMASK=255.255.255.0
NETWORK=172.16.1.0
BROADCAST=172.16.1.255
ONBOOT=yes
BOOTPROTO=none


Restart networking using the command /etc/rc.d/init.d/network restart, and the subinterface will be set.

NAT types
You generally use NAT for one of two reasons. The primary reason would be if you don't have enough public IP addresses for all of the devices that you need to connect to your network. With NAT, you can get by with just one outside address for all of your internal devices. The secondary one would be to provide a measure of security. By translating the outgoing addresses from an address in one of the private ranges to a public address, you are protecting the identity of the internal machine and therefore shielding it from attack.

There are two types of NAT, source NAT (SNAT) and destination NAT (DNAT). SNAT modifies the source IP address, effectively changing the origination address of the packet. DNAT modifies the target IP address of the packet. IP masquerading is a form of SNAT; port forwarding and transparent proxying are forms of DNAT. I will be focusing on SNAT in this article.

IP addressing
There are two IP addressing components involved in NAT: public side and private side. The public side is the connection to your Internet provider; the private side consists of addresses that you will assign to your internal devices from a special pool of IP addresses set aside for this type of application. Below is a listing of private IP address ranges.
  • ·        10.0.0.0 - 10.255.255.255
  • ·        172.16.0.0 - 172.31.255.255
  • ·        192.168.0.0 - 192.168.255.255

None of the addresses on the list above can be used as public side addresses. So to use them on your network, you need to employ technology such as NAT that disguises these private addresses from the Internet with a public address.

What is iptables?
Linux's iptables is the firewalling, NAT, packet filtering, and general multipurpose networking component in the Linux 2.4 kernel. It replaces ipchains, which was found in the 2.2 kernel.

Installing the iptables
If you didn't install iptables on your Linux server during installation, you can download the latest version from the NetFilter Web site. As of this writing, the latest version is 1.26a and the filename is ip-tables.1.2.6a.tar.bz2. Place this archive in your /usr/src directory.

Use these commands for installing iptables:
cd /usr/src
bunzip2 iptables-1.2.6a.tar.bz2
tar xvf iptables-1.2.6a.tar
cd iptables-1.2.6a
make
make install


A simple process
Setting up NAT is simple when using iptables. On a Linux server, you must execute two primary tasks. First, you must turn on forwarding in one of the system TCP/IP configuration files. To do so, type the command echo 1 > /proc/sys/net/ipv4/ip_forward at the system prompt.

Running the above command is the same thing as manually editing this file and placing the number 1 in it. Either way, you are enabling IP forwarding on the system. To turn it off, simply delete the /proc/sys/net/ipv4/ip_forward file.

Next, you must start the iptables system with the /etc/rc.d/init.d/iptables start command before you can begin feeding it commands. .

Finally, you need to give iptables a specific rule to enable IP masquerading. To add such a rule to the system, run the command /usr/local/sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE.

The first part of this command is the path to the iptables executable. The -t nat directive indicates that this rule is to be added to the NAT table. The -A directive says to append the rule POSTROUTING after routing takes place. The -o eth0 directive tells iptables to process packets exiting via eth0. Finally, the -j MASQUERADE directive tells iptables to perform NAT on this connection.

Simple, eh?

Adding a second rule to the list will allow you to log every packet that goes through your NAT server. To add this rule, run the command /usr/local/sbin/iptables -A FORWARD -j LOG.

Testing it
Move over to your Windows 2000 server that you've placed behind the Linux NAT server. In my case the Windows 2000 server’s default gateway is set to 172.16.1.1, which is the internal interface on my NAT server and provides DNS on my external network. From the Windows 2000 server, try to browse to any Web site. It should work.

When you look at the messages log on your Linux server after browsing a Web site, you should see the packets. Listing A shows an example of a /var/log/messages entry from my Linux server.

As you can see, from the Linux servers log file, the Windows 2000 server, 172.16.1.2, was able to reach the destination address, 209.185.242.251 even though it is not directly connected to the outside world.

A common, and dangerous, mistake 
/usr/local/sbin/iptables -t nat -A POSTROUTING -j MASQUERADE

The command above is similar to the one I used in the previous example, but it omits the name of the interface. This can open up your network to major attacks. Not specifying the adapter to use for NAT enables NAT in both directions. Basically, someone could enter your network using the same method that you use to protect it. To keep this from happening, make sure you define which adapter that NAT will be applied to.

To provide even more protection for your network, you can specify an additional parameter in your iptables command, allowing NAT to take place only for specific incoming addresses, which would help prevent unauthorized NAT on your network.

In the sample iptables rule above, I want to allow NAT from machines only on the 172.16.1.0/255.255.255.0 network. So I'll use the iptables command /usr/local/sbin/iptables -t nat -A POSTROUTING -o eth0 -s 172.16.1.0/24 -j MASQUERADE.

If you need to add more than one network range to this, all you have to do is to repeat this command, simply replacing the source (-s) network range with the new one.

Additional parameters
In addition to the source parameter (-s), there are additional parameters that you can specify to further control your NAT application. First, if you only want to allow specific machines to go to specific destinations, you can use the -s parameter in conjunction with the destination (-d) parameter. The destination parameter uses the same syntax as the source parameter, but will use a public IP address assigned to the outside interface or the Internet.

You can also use the -p parameter to effectively allow only specific protocols such as HTTP or FTP, or even just TCP applications.

The /usr/local/sbin/iptables -t nat -A POSTROUTING -o eth0 -s 172.16.1.0/24 –d 204.202.132.19 -j MASQUERADE command is an example of a NAT rule that will allow a connection only to www.abcnews.com and only from the 172.16.1.0/24 network.

Unfortunately, this example omits some very important features. It does not take into consideration the DNS servers. Since no access is allowed to them, I am unable to browse to any destination via the host name, but I can do so via IP address.

To solve this problem I will add two rules. The first rule, /usr/local/sbin/iptables -t nat -A POSTROUTING -o eth0 -s 172.16.1.0/24 -p 53 -j MASQUERADE, will allow DNS connections to any IP address from my internal network. The second rule, /usr/local/sbin/iptables -t nat -A POSTROUTING -o eth0 -s 172.16.1.0/24 -p 80 -j MASQUERADE, will allow only HTTP connections.

Make it permanent
If you don't want to have to retype all of these commands when you reboot your server, I would suggest creating a bash script that will run each, and then starting that bash script on boot with the rc.local file.

The content of the bash script will look like:
#! /bin/sh
# allow forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# start iptables
/etc/rc.d/init.d/iptables start
# enable masquerading
/usr/local/sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# enable logging
/usr/local/sbin/iptables -A FORWARD -j LOG


Save the above script in your /usr/local/ file, name it iptables_nat, give it executable permissions (as root) with chmod u+x /usr/local/iptables_nat, and then add the entry /usr/local/iptables_nat at the end of your /etc/rc.d/rc.local file. Make sure you make necessary modifications to the above script to meet the needs of your network.

The flexible iptables
As illustrated above, iptables makes for simple network address translation. But don’t forget its primary function: security. Linux’s iptables is a powerful firewall tool that has the potential to help you to solve other network problems, such as the IP address shortage issue.

Editor's Picks

Free Newsletters, In your Inbox