I wrote a detailed explanation of how DNAT works

Ian! D. Allen [NCFreeNet] idallen@freenet.carleton.ca
Wed, 31 Jul 2002 12:44:48 -0400


Is this verbose explanation of DNAT (a) accurate and (b) useful to you?

I wrote it because Rusty's explanation, while (a) correct and accurate,
didn't (b) quite let me visualize what was going on.

========================================================================
A Detailed Description of Destination Network Address Translation (DNAT)
========================================================================
(c) 2002 Ian! D. Allen <idallen@freenet.carleton.ca> Ottawa, Canada
    This is a FREE document.  See the Copyright info at the end.

DRAFT #1  July 31, 2002

This is a detailed description of how Destination Network Address
Translation (DNAT) works.  It is based on hints given by Rusty Russell
in the NAT-HOWTO.linuxdoc.html.  If reading Rusty's explanation isn't
quite enough for you, try this one.

Why DNAT?
----------

You may not want to run a web server directly on your
router/firewall/gateway machine.  (Most books on security discourage it.)

You would like to arrange that when someone on an external public network
(e.g. the Internet) makes a connection to the web port (80) of your
router's public address (e.g. www.yourhost.ca), they are transparently
redirected to a web server running on a machine in your internal network,
hidden safely behind the router.  You want anyone trying to get to port
80 on the router to be redirected to port 80 on this web server machine
on your internal network.

In addition to having clients on machines on external networks redirected
to your web server, you also want clients on your internal networks to be
redirected to the same internal web server, using the same web addresses.
(Up until Linux kernel 2.4, this wasn't easy; now, it is.)

You can do both of these redirections with DNAT (Destination Network
Address Translation), plus some trickery involving a bit of SNAT (Source
Network Address Translation).

Three Network Interface Addresses
---------------------------------

Suppose you have a router/firewall/gateway machine connected to three
networks: an external public network 100.0.0.0, an internal DMZ network
172.16.0.0, and an internal trusted network 192.168.0.0.  You do standard
SNAT or MASQUERADE to allow the two internal networks to masquerade their
packets out the public network interface.  (See elsewhere for how to do
standard outgoing SNAT or MASQUERADE using the iptables/netfilter tools.)

Your router, being connected to three networks, actually has three
network interface addresses: a public external address 100.0.0.254,
an internal DMZ interface address 172.16.0.254, and an internal trusted
interface address 192.168.0.254.  (Your actual addresses may differ.)

In reality, machines don't have IP addresses; their network cards have
IP addresses (and sometimes even several addresses).

Thus, "port 80 on the router" means "port 80 on any of its three network
interfaces", i.e. port 80 on 100.0.0.254, port 80 on 172.16.0.254,
and port 80 on 192.168.0.254.

Diverting packets using DNAT
----------------------------

The first step is to arrange that any packets destined for "port 80 on
the router" get routed to port 80 on the internal web server.

Since the router has three network interface addresses, it takes three
DNAT rules to route each of the three possible router destination
addresses to the same internal web server address.  Let's put the web
server on IP address 172.16.0.1 (on the DMZ network) for this example.

Here are the three rules using three iptables command lines; the only
differences among the three are the destination (-d) address in each:

    iptables -t nat -A PREROUTING -d 100.0.0.254 \ 
	-p tcp --dport 80 -j DNAT --to 172.16.0.1

    iptables -t nat -A PREROUTING -d 172.16.0.254 \ 
	-p tcp --dport 80 -j DNAT --to 172.16.0.1

    iptables -t nat -A PREROUTING -d 192.168.0.254 \ 
	-p tcp --dport 80 -j DNAT --to 172.16.0.1

Each DNAT rule will rewrite the destination address to be 172.16.0.1 (--to
172.16.0.1) in incoming client packets that have a current destination
address (-d addr) of one of the router's network interfaces.  The DNAT
performed by the router removes the original destination address in
the packet (destined to be one of the three router network interface
addresses) and replaces it with the destination address of the internal
web server (--to 172.16.0.1) on the DMZ network.

The port part of the packet remains untouched in this example; only
the destination IP address is changed by the DNAT rule in the router.
You could also route the packet to a different port on the internal web
server by modifying the --to argument.

Remembering the destination address - un-DNAT
---------------------------------------------

A DNAT rule on the router *remembers* the original destination address
to which a packet was addressed; the router does not "throw away"
the original destination address.  With each DNAT rule there is a
corresponding un-DNAT mechanism on the router that will un-rewrite the
corresponding web server reply packets as they come back through the
router back toward the client.

The un-DNAT mechanism in the router replaces the source address of the
reply packets with the remembered original destination address saved
by DNAT, before relaying the web server packet back to the client.
This makes the web server reply packets look as if they came from the
original destination (from the router, which is to where the client
originaly sent the packet).

Note that the router's DNAT rule changes the *destination* address for
inbound packets from the client, while the corresponding un-DNAT mechanism
changes the corresponding *source* address in the reply packets that
come back from the web server.  DNAT makes the incoming client packet
look like it was destined for the internal address of the web server,
while un-DNAT makes the web server reply packet look like it came from
the router.  More on un-DNAT later.

The router must DNAT all the inbound packets for the client and un-DNAT
all the reply packets from the web server for this masquerading to work.

The external client will know nothing about the internal web server.
The router uses DNAT to put the internal web server destination address
into incoming client packets that go to the internal web server, and
the router's un-DNAT mechanism replaces the internal web server source
address with one of its own network addresses before sending the return
packet from the web server back to the client.  The internal web server
address never appears in packets returned to the client via the external
public interface.

In the above code example, the router uses DNAT to take an incoming
client packet destined for port 80 on any of the three router network
interfaces (the router has network interface addresses 100.0.0.254,
172.16.0.254, or 192.168.0.254) and routes the incoming client packet
to the internal web server at 172.16.0.1 on the internal DMZ network.
DNAT does this by rewriting only the destination address of the packet.

The un-DNAT mechanism will happen automatically when the internal web
server sends a reply packet back through this same router.  The router
will use the address saved by DNAT to un-DNAT the reply packet, making
it appear as if the reply came from the router, not from the internal
web client.

Thus an external client packet arriving from the Internet with source
address 123.45.6.7 and destination of port 80 at address 100.0.0.254
(one of the three router network interface addresses) gets rewritten
by the router DNAT rule to have destination address 172.16.0.1 (the
internal web server), and the packet is then forwarded for delivery to
the internal web server on the DMZ network.

The original destination address 100.0.0.254 (router) in the incoming
client packet is remembered by the router's DNAT rule and will be used
by the un-DNAT mechanism to replace the source addresses of reply packets
coming back from the web server to the client.  Let's see how that works.

Replies to the DNAT client packet
---------------------------------

The web server on the hidden internal DMZ network receives DNAT'ed packets
from the external client that come via the router.  Let's examine how
the reply packets from the web server return to the router for un-DNAT,
and then go on to the client.

The reply process depends on whether the original client that sent the
packets to the router for DNAT is on the same network as the internal
web server (on the same DMZ 172.16.0.0 network), or is on a different
network (e.g. the client may be on the external public network or on
the other internal network 192.168.0.0 in our example).

No matter from where the client packet originates, the router applies
DNAT in the same way - the router always replaces the destination address
in the client packet with the address of the internal web server and
delivers the packet to the web server.

How the web server replies to the packet it gets from the router changes
depending on where the client and server are with respect to each other.

Replies with client and server on different networks
----------------------------------------------------

Here's how the replies from web server to router to client work (assuming
a client that is *NOT* on the same network as the internal web server):

The web server, upon receiving a DNAT'ed packet from the client via the
router, constructs a reply packet.

If the source address of a client packet appears to the internal
web server to be on a different network from the web server, the web
server must send the reply packet back to the client via the network
gateway interface.  (A gateway interface is where you send packets for
destinations that are not on your local network.)  The gateway machine for
the web server's DMZ network 172.16.0.0 is 172.16.0.254, the DNAT router.

Thus, if the initial client packet comes via the router from a different
network, the internal web server must send the reply to the client back
through the router (because the router is the gateway) and let the router
forward it.  This gives the router the chance to un-DNAT the
web server packet before delivering it back to the client.

Thus the router is correctly involved in the DNAT translation
of client-->router(DNAT)-->server and the un-DNAT translation of
server-->router(un-DNAT)-->client, and the exchange correctly has both
DNAT and un-DNAT parts to it.  The client thinks it is talking to the
router, not the internal web server.

For example, a client packet from Internet host 123.45.6.7 destined
for port 80 on the router's external public interface 100.0.0.254 gets
rewritten by DNAT in the router.  DNAT replaces the original packet
destination 100.0.0.254 by the internal web server destination 172.16.0.1.
The rewritten packet moves on to the 172.16.0.0 network for delivery to
the internal web server.  The original destination address (100.0.0.254)
is saved and remembered by the router for use by un-DNAT later.

The internal web server at 172.16.0.1 receives the DNAT'ed incoming
client packet from the router and constructs a reply.  The incoming
packet still has an Internet source address (unchanged) of 123.45.6.7.
This becomes the destination address for the reply packet from the web
server back to the client.  Since reply destination 123.45.6.7 is not on
the same network as the internal web server (not on network 172.16.0.0),
the web server sends the reply packet destined for 123.45.6.7 to the
gateway machine for the 172.16.0.0 network - that is, to the router
at 172.16.0.254.

The router is expecting the reply packet from the internal web server,
having just sent it the DNAT'ed client packet.  The router receives
the reply from the web server and applies the un-DNAT mechanism to the
source address of the web server reply packet.  The un-DNAT removes the
internal web server source address 172.16.0.1 and replaces it with the
saved (by DNAT) source address 100.0.0.254.  (This is the opposite
of what the router did with DNAT to the incoming client packet in the
first place.  This un-DNAT mechanism makes the reply packet from the
internal web server look as if the router was its actual source.)

Now the reply packet from the internal web server, destined for the client
and having passed through un-DNAT, appears to have a source address of
the router (100.0.0.254), not of the internal web server (172.16.0.1).
The translated reply packet is forwarded to the original client at
123.45.6.7 on the Internet.  The original client sees the router's
external address (100.0.0.254) as the source of the packet.

Further exchanges between the client and server repeat this sequence,
using the router as the DNAT translator both ways.  In every incoming
client packet, the router uses DNAT to change the destination address
100.0.0.254 to be the internal web server address 172.16.0.1.  The
original destination address is saved by the router.  For every reply
packet coming from the internal web server, the router does un-DNAT to
change the internal web server source address 172.16.0.1 back to the saved
router external public address 100.0.0.254.

Things work fine, as long as the client and internal server are
on different networks that require the packets to pass through the
DNAT/un-DNAT gateway in both directions.

Failed replies with client and server on the same network
---------------------------------------------------------

The DNAT/un-DNAT process in the router stops working if the web client
and internal web server are on the *same* network.  This usually happens
with small sites where there is no DMZ network and both the client
machines and the internal servers are on the one single internal network.
Someone on the internal network tries to access the web site using one
of the router's three network addresses (often the public one, visible
from the Internet), and that times out and fails.

The DNAT/un-DNAT only fails if the the client is on the same network
as the internal web server, e.g. a client on the DMZ at 172.16.0.2 with
the internal web server also on the DMZ at 172.16.0.1.  Here's why:

Let's assume we have a client at address 172.16.0.2 on the internal
network and the internal web server is still at 172.16.0.1 on the same
network.

The initial packet from the client (at 172.16.0.2) to one of the router's
three interface addresses (e.g. to 172.16.0.254) does a rather odd dance,
when the client is on the same internal network as the web server.

The client packet, incoming from 172.16.0.2 on the internal network
to port 80 on 172.16.0.254 (the router), gets correctly rewritten by
DNAT in the router to have a destination address of the web server at
172.16.0.1 on the internal network, causing the client's packet that
came in from the internal network to go right back out the same network
interface into which it came!

Normally this kind of network nonsense is considered an error, and an
ICMP redirect packet would be generated telling the client not to make
that mistake in future; only since kernel 2.4.0 has this redirect packet
been suppressed for DNAT'ed packets.  The packet from the client comes
in on the 172.16.0.0 network and is DNAT-redirected right back out the
same interface, to arrive correctly at the web server.  So far so good.

When the internal web server at 172.16.0.1 builds its reply to this
incoming client packet from 172.16.0.2, its reply must naturally go to
the source address that sent the packet.  But the source address of this
packet is the (unchanged) client address 172.16.0.2 - this address is
correctly seen by the web server as being on the *same* network as itself.

Because the source address of the packet is on the same network as itself,
the web server mistakenly thinks that it received the packet directly
from the client, and it prepares to reply directly to the client, without
going via the router.  As we have seen, the client packet actually came
from the router via DNAT, and it is the *router* that is expecting the
reply, not the client.

The web server sends its reply packet directly from itself at 172.16.0.1
to the client at 172.16.0.2 without using the gateway router host at
172.16.0.254.  (Machines on the same network communicate directly with
each other - they don't use the gateway machine that is needed when
sending packets between different networks.) 

The client at 172.16.0.2 is not expecting any packets to arrive
directly from the web server at 172.16.0.1; the client is expecting a
reply packet from port 80 on the router at 172.16.0.254.  So the client
throws away the bogus unexpected packet from 172.16.0.1, and all other
packets arriving directy from the internal web server.  The connection
eventually times out.

This type of reply failure happens only when the client machine is on
the same network as the internal web server.  The web server incorrectly
sends its replies directly to the client, instead of passing the replies
through the router for proper un-DNAT and return to the client.

Making clients on the same network reply to the router
------------------------------------------------------

The trick we can do to repair this unintended reply error, when the client
and the server are on the same network, is to ensure that packets coming
from the router are always returned to the router.

The idea is to make sure that the DNAT'ed packets arriving at the
web server from the router will *always* get sent back to the router
for un-DNAT, even if the client and server are on the same network.
The replies must not get short-circuited and go direct from the web
server to the client.

We can ensure that the reply packets always get returned to the router
by altering the *source* address of the incoming client packets so that
they always appear to be *from* the router, not from the client.  To alter
packet source addresses, we use Source Network Address Translation (SNAT).

The router will also apply SNAT to the already DNAT'ed client packets
being sent from the router to the internal web server.

We add a SNAT rule (in addition to the above DNAT rules) that changes
the source addresses of packets destined for the web server, if their
source addresses are on the same network as the web server:

    iptables -t nat -A POSTROUTING -s 172.16.0.0/24 -d 172.16.0.1 \
    	-p tcp --dport 80 -j SNAT --to 172.16.0.254

With the above SNAT rule, any already-DNAT'ed client packet destined
for the web server (-d 172.16.0.1) that has a source address on the
same network as the web server (-s 172.16.0.0/24) will have its source
address changed from whatever IP address it might have on the internal
network (e.g. 172.16.0.2) to to be the IP address of the router network
interface (--to 172.16.0.254).  This guarantees that the web server will
generate a reply *to the router*, not to the client.

Just as with DNAT, the original address being replaced by SNAT is saved
for later use by un-SNAT when the reply packet comes back from the
internal web server.  DNAT saves the original destination address for
use by un-DNAT; SNAT saves the original source address for use by un-SNAT.

The above SNAT POSTROUTING rule is traversed *after* the DNAT PREROUTING
rule that changes the destination address to be the web server; so,
by the time we look at the packets in the SNAT rule, the destination
addresses will have already been translated by DNAT from the original
router address 172.16.0.254 to be the web server address 172.16.0.1 by
the DNAT rule.  So the above SNAT rule matches packets that have been
DNAT'ed to go to the web server, and that have a source address anywhere
on the same network as the web server (172.16.0.0/24).

The incoming client packet that the web server finally sees, having been
through both DNAT and SNAT at the router, will have had the destination
address changed by DNAT from 172.16.0.254 (router) to 172.16.0.1 (web
server), and the source address changed by SNAT from 172.16.0.2 (client)
to 172.16.0.254 (router).  The web server naturally generates a reply
to this incoming client packet using itself 172.16.0.1 (web server)
as the source and 172.16.0.254 (router) as the destination.  The server
reply packet goes to the router, as desired.

When the reply packet from the web server arrives back at the router,
the router recognizes that this packet requires both un-SNAT and un-DNAT.
Since the router processed the original client packet using DNAT followed
by SNAT, the router handles the reply packet using un-SNAT followed
by un-DNAT.

Just as a DNAT rule changes the *destination* address of a packet, and
its corresponding un-DNAT mechanism changes the *source* address of a
reply packet, the SNAT rule changes the *source* address of a packet,
and its corresponding un-SNAT mechanism changes the *destination*
address of a reply packet.

The first thing the router does is to apply the un-SNAT mechanism to
the *destination* address in the reply packet from the web server.
(SNAT changes a *source* address; un-SNAT changes a *destination*
address.)  The un-SNAT mechanism removes the current destination
address of 172.16.0.254 (router) and replaces it with the original
source address that was saved by SNAT when it translated the source
address of the original incoming client packet: 172.16.0.2 (client).
(Recall that the SNAT changed the source address from 172.16.0.2 (client)
to 172.16.0.254 (router) on the incoming client packet and saved the
original source address.)

Second, the router applies the un-DNAT mechanism to the *source* address
in the reply packet from the web server.  (DNAT changes a *destination*
address; un-DNAT changes a *source* address.)  The un-DNAT mechanism
removes the current source address of 172.16.0.1 (web server) and
replaces it with the original destination address that was saved by
DNAT when it translated the destination address of the original incoming
client packet: 172.16.0.254 (router).  (Recall that the DNAT changed the
destination address from 172.16.0.254 (router) to 172.16.0.2 (client)
on the incoming client packet and saved the original destination address.)

The result, after the router applies both un-SNAT and un-DNAT, is a
reply packet that originally arrived from the web server to the router
with source address 172.16.0.1 (web server) and destination address
172.16.0.254 (router) now has new source address 172.16.0.254 (router)
and new destination address 172.16.0.2 (client).

After both un-SNAT and un-DNAT, the reply packet continues correctly back
to the client on the internal network, from the router, just as the client
expects.  The next exchange between the client on the internal network
and the web server on the same internal network repeats the process: every
packet from the client has both DNAT followd by SNAT applied; every reply
packet from the internal web server has both un-SNAT and un-DNAT applied.

The internaln network client packet travels through both DNAT and
SNAT to the server (client-->router(DNAT+SNT)-->server) the server
reply travels through both un-SNAT and un-DNAT back to the client
(server-->router(un-SNAT+un-DNAT)-->client).  The client (via DNAT)
thinks it is talking to the router, not the internal web server, as
before; but, the web server (via SNAT) also thinks it is replying to
the router, not to the client.

Two machines on the same network that would normally communicate directly
have been fooled by SNAT into sending their packets via the router.

Many clients - too much SNAT
----------------------------

If you have many servers on your internal network receiving packets via
DNAT, you could find yourself writing a lot of extra SNAT rules to make
the individual servers work with clients on the same networks.  You can
simplify all the the SNAT rules for a network to just one:

    iptables -t nat -A POSTROUTING -s 172.16.0.0/24 -d 172.16.0.0/24 \
    	-j SNAT --to 172.16.0.254

Instead of specifying the the exact destination IP address of the internal
web server, use a network expression (-d 172.16.0.0/24) so that *all*
packets that have both source and destination on the internal network
will also have the SNAT rule applied.  The above rule ensures that any
packets being sent out onto the internal interfaces using DNAT will
have a return (source) address of the router, no matter what their
destination protocol, port, or specific IP address.

With the above SNAT rule, *all* services on the internal network are
available to clients on the same internal network, not just the single
internal web server.

Summary
-------

A complete set of DNAT rules for a three-network router forwarding to
port 80 on an internal web server:

    iptables -t nat -A PREROUTING -d 100.0.0.254 \ 
	-p tcp --dport 80 -j DNAT --to 172.16.0.1
    iptables -t nat -A PREROUTING -d 172.16.0.254 \ 
	-p tcp --dport 80 -j DNAT --to 172.16.0.1
    iptables -t nat -A PREROUTING -d 192.168.0.254 \ 
	-p tcp --dport 80 -j DNAT --to 172.16.0.1

The two SNAT rules that make clients and servers on the two internal
networks find each other correctly via the router:

    iptables -t nat -A POSTROUTING -s 172.16.0.0/24 -d 172.16.0.0/24 \
    	-j SNAT --to 172.16.0.254
    iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -d 192.168.0.0/24 \
    	-j SNAT --to 192.168.0.254

Copyright
---------

Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1
or any later version published by the Free Software Foundation.
http://www.tldp.org/

-- 
-IAN!  Ian! D. Allen   Ottawa, Ontario, Canada   idallen@ncf.ca
       Home Page on the Ottawa FreeNet: http://www.ncf.ca/~aa610/
       College professor at: http://www.algonquincollege.com/~alleni/
       Board Member, TeleCommunities CANADA  http://www.tc.ca/