IP Masquerading with Linux

A few months ago, Chris concluded an article on building a Linux firewall with an allusion to Linux's ability to hide an entire network behind a single IP address—called IP masquerading. This month, he explains how to enable and configure IP masquerading, also known as Network Address Translation, for Linux.

It seems everyone wants on the Internet nowadays, and for good reason. There is plenty of information to obtain, people to send e-mail to, web pages to look at and software to download. Besides that, businesses are finding acceptable means of advertising, and in some cases, selling merchandise. But with all the rush to get on the Internet, people are finding Internet addresses are not as readily available as they once were. Some network administrators are experiencing that in many environments; they don't have enough network addresses to meet the demand.

Instead of going through the motions of obtaining another block or two of class C addresses, some administrators hide a set of unregistered addresses behind a network address translation (NAT) device. The Internet is prepared for these “private” addresses, and blocks of addresses are reserved for this purpose. RFC 1597 specifies the addresses through, through, and through to be used in these instances.

The RFC strongly recommends that if you, as a network administrator, are going to use a private address, you should select addresses from the ranges given. One notably important reason is that if a packet happens to pass through the NAT with its original IP address intact, the backbone routers on the Internet will not forward the packet. If, instead, you were using someone else's valid IP address, confusion could occur.

Many firewalls, especially those based on application proxy gateways, naturally hide addresses because of how they function. It is no surprise that Linux can also support address hiding through what is called “IP masquerading”. Setting up masquerading under Linux is not terribly difficult, but there are some subtleties to point out.

Getting Ready

If you are running kernel version 1.2.x, you need to obtain the kernel patch to support masquerading. The patch is available from ftp://ftp.eves.com/pub/masq, or you can download everything you need from www.indyramp.com/masq/. IP masquerading is supported with 1.3.x kernel versions. For this article, I was running version 1.3.56, and all examples are based on this version. For FTP support (mentioned later), you need to have at least kernel version 1.3.37. There is a patch for 1.2.x (where x >= 4) kernels to support FTP, but I haven't tested it yet. The masqplus-0.4 “jumbo” patch that is available from Indyramp fixes a few bugs and adds support for FTP, RealAudio, and fragmentation for 1.2.13 kernels.

When configuring the kernel to support masquerading, it is important to also say yes to firewall and forwarding support. Here are the parameters I used for configuring my kernel:

Network firewalls (CONFIG_FIREWALL) [Y/n/?] y
Network aliasing (CONFIG_NET_ALIAS) [Y/n/?] y
TCP/IP networking (CONFIG_INET) [Y/n/?] y
IP: forwarding/gatewaying (CONFIG_IP_FORWARD) [Y/n/?] y
IP: multicasting (CONFIG_IP_MULTICAST) [Y/n/?] y
IP: firewalling (CONFIG_IP_FIREWALL) [Y/n/?] y
IP: accounting (CONFIG_IP_ACCT) [Y/n/?] y
IP: tunneling (CONFIG_NET_IPIP) [Y/m/n/?] y
eP: firewall packet logging (CONFIG_IP_FIREWALL_VERBOSE) [Y/n/?] y
IP: masquerading (ALPHA) (CONFIG_IP_MASQUERADE) [Y/n/?] y

I chose other items not directly related to masquerading such as multicast and tunneling, but I like to have fun.

Notice the IP masquerading software is still considered to be Alpha-quality. This means there are probably still some bugs. The base functionality is there, but not all of the nuances of TCP, UDP, and IP, nor the application protocols, have been thoroughly tested. In addition, the interface may still change as development proceeds.

In order to manipulate the masquerading ruleset, you will need the ipfw software version 1.3.6-BETA3, or you can obtain a precompiled binary from ftp.eves.com. Those who use Linux as a filtering firewall and also use ipfwadm should note that software does not yet support IP masquerading, so ipfw is necessary. [New: ipfwadm 2.0beta2, now available for Linux 1.3.66 and newer from ftp://ftp.xos.nl/pub/linux/ipfwadm/, does support masquerading. Also, it is necessary to use recent versions of ipfwadm with the most recent versions of the kernel due to interface changes—ED]

Applying the Rules

Let's first define what we're trying to accomplish and see how IP masquerading is useful in the environment. Figure 1 shows the networks on which the examples are based. deathstar is the Linux machine employing masquerading in order to hide the network

Masquerading is useful in our architecture because it saves us a little administrative hassle. A number of people in my department have home LANs, and through their PPP connection they can use their other machines to connect to the department lab. We could easily run a routing protocol, like RIP, to make the machines on the lab network aware of the home LANs, but that would take some coordination about who has what network address. It is easier (for us) to use masquerading.

To hide the network, we can issue the command:

# ipfw a m all from to

This rule indicates that we want to add a masquerading rule for all protocols (which in this case means TCP and UDP). The network we are hiding is, and we are hiding connections going to any network ( The /24 indicates we are applying a 24-bit netmask, or Since we specified the network as, deathstar will masquerade for all hosts on the network. That's all we need to do.

If I had only wanted deathstar to masquerade for enterprise, then I would have typed in:

# ipfw a m all from to

But what does it really mean “to masquerade for”? Well, let's examine the affected files and kernel tables for a typical masqueraded connection. We'll use telnet for our example.

Let's verify the rule has been set. We need to look at the ip_forward file in the /proc/net directory. We can use ipfw to do this:

# ipfw -n list forward
Type    Proto       From           To     Ports
(masqueradeall  anywhere

This is good. Some administrators mistakenly look in the /proc/net/ip_masquerade file for the rule and when they don't see it, confusion sets in.

For our example, I've started a telnet session from warbird to enterprise. Also, on mccoy, I'm using the tcpdump program to monitor the traffic on and sparcbook to monitor the traffic on We can now look at the ip_masquerade file to examine what is happening (see Listing 1).

Let's decode this stuff. First, the earliest packet is at the bottom. It is a DNS request (therefore UDP) from to mccoy is warbird's DNS server in this case. The Masq column shows us the port on deathstar that is used for the masquerading. For the first DNS request, it is port 60000 (EA60). After the DNS resolution, the TCP connection is established on the next available port over 60000, 60001. Figure 2 illustrates the protocol time-line for the sequence of events up to the TCP open.

Even though the protocol time-line shows how the packets really traverse, the sending and receiving nodes are unaware of this. Hence, the reason they call it masquerading. From warbird's point of view, the traffic will look exactly as expected. That is, packets from enterprise are repackaged by deathstar to look as if they came from enterprise. Listing 2 shows the tcpdump output of the traffic on the network for the telnet session.

Listing 3 shows the protocol traffic on the network during the telnet session. Notice that information originates from deathstar, not warbird. (Another thing you might notice is I don't keep the clocks synchronized very well.)

Another important aspect is maintaining the TCP synchronization numbers. For masquerading to work properly, deathstar must keep the synchronization correct. The TCP sequence number generated by warbird is forwarded by deathstar rather than a new sequence number being generated.

Some final observations about the contents of the /proc/net/ip_masquerade file pertain to the last four fields. The Init-seq, Delta, and PDelta fields deal with the TCP synchronization numbers when ftp data transfers (more in a minute) occur, and the last field is the expiration timer on the masquerade entry. The time is kept in hundredths of seconds; TCP is given 90000 or 15 minutes, and UDP is given 300000 or 5 minutes. As long as traffic is being passed between the two communicating hosts for the masked port, the timer will remain updated. A minor detail about the expiration timer has to do with FTP transfers. FTP uses two connections: a control connection for commands and a data connection for a file transfer. While the data connection is in use for data movement, the control connection will sit idle. If the transfer takes longer than 15 minutes, the masquerading host will close the control connection. The data connection will go to completion, but you will have to reconnect if you want to get more files. This is controlled by the definitions:

#define MASQUERADE_EXPIRE_TCP     15*60*HZ
#define MASQUERADE_EXPIRE_UDP      5*60*HZ

in the file /usr/include/linux/ip_fw.h. Six hours (360 minutes) seems to be a relatively acceptable timeout value, but change it as you see fit.