How do SNAT and DNAT work on Linux?

adil
4 min readJan 12, 2024

--

Source NAT (SNAT) and Destination NAT (DNAT) are the backbone rules of networking.

Photo by 愚木混株 cdd20 on Unsplash

SNAT is generally used when network traffic goes from a private network to a public network.

DNAT is often used when network traffic goes from a public network to a private network.

These are accurate boilerplate descriptions of SNAT and DNAT found on the internet.

I would like to define SNAT and DNAT in another way that I believe is easier.

An example setup:

You have 3 servers:
Server A (10.0.0.10)
Server B (10.0.0.20)
Server C (10.0.0.30)

You can not control Server C.
However, Server A and Server B are under your control.

Server C has a MySQL database listening to Port 3306.

Server A can access all of Server B’s ports.
Server A can not access any ports of Server C.
Server C’s Port 3306 can only be accessed from Server B.

Let’s observe this setup:

Can Server A access Server C’s Port 3306?

Yes, thanks to SNAT and DNAT.

In this case, Server B will act as a router for Server A.

Since Server B will act as a router, we must enable IP forwarding on Server B.

echo 1 > /proc/sys/net/ipv4/ip_forward

Let’s choose a random port on Server B. Server A will send the request to this port on Server B instead of Port 3306 on Server C.

Let’s say: Port 1122 on Server B

Server B will forward traffic from Port 1122 to Server C’s Port 3306.

iptables rule:

iptables -t nat -A PREROUTING -p tcp --dport 1122 -j DNAT --to-destination 10.0.0.30:3306

nftables rule:

nft add rule ip nat PREROUTING tcp dport 1122 counter dnat to 10.0.0.30:3306

P.S.: Use the nftables rule or the iptables rule.

This rule changes the destination (Destination NAT) of the traffic.

Let’s try to connect to Port 1122 from Server A:

Server A cannot access Server B’s Port 1122.

Let’s examine the network traffic on Server B via iptraf
(see: How to monitor the network activity of a specific IP via IPTraf?)

The first two lines show my SSH connection. Ignore them.

Traffic from Server A (10.0.0.10) to Port 1122 of Server B (10.0.0.20) can be seen. At the bottom of the list, you can see traffic directed to Server C (10.0.0.30).

A request was made from Server A to Server B.

Why did it time out?

The problem is that Server B sets the source IP of the forwarded traffic to Server A’s IP address.

Traffic flow is disrupted.

Server A is waiting for a response from Server B. Server C should send a response to Server B.

Therefore, we must change the source IP of the network packet on Server B. We achieve this by setting a SNAT (Source NAT) rule on Server B:

iptables rule:

iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 10.0.0.20

nftables rule:

nft add rule ip nat POSTROUTING oifname "eth0" counter snat to 10.0.0.20

Let’s try again:

Server A can connect to the MySQL server on Server C!

Let’s examine the network traffic on Server B

Traffic goes from 10.0.0.10 (Server A) to 10.0.0.20 (Server B).
Its source IP was altered on Server B.
The modified traffic goes from 10.0.0.20 (Server B) to 10.0.0.30 (Server C).

This is how SNAT and DNAT work.

--

--