Redirect Traffic to Server in LAN with Iptables Jul 7th 2018 Words: 696
This post is created 2 years ago, the content may be outdated.

Background

I have HDDs full of hentai personal data. I am hosting the SMB/FTP/NFS service on the server with static IP 192.168.100.100/24, and all applications on the clients use 192.168.100.100 to reach the server. It works without problem until I migrate the server temporarily under another router 192.168.1.1/24. Now I would like to still use the IP 192.168.100.100 to access all service on 192.168.1.100 in order to avoid modifying a s**tload of configuration files on the clients. Using hostname rather than IP address is a better solution. However my clients are using localhost DNS and will ignore the result of the router.

DNAT

On the router using the following iptables command to redirect all package whose original destination is 192.168.100.100 to 192.168.1.100.

1
iptables -t nat -I PREROUTING -d 192.168.100.100 -j DNAT --to-destination 192.168.1.100

After the DNAT setting, if a client 192.168.1.114 tries to send a request packet to 192.168.100.100, the following process will happen.

The client first will check the destination IP address 192.168.100.100, find this address is not in the LAN 192.168.1.0/24.

It then sends the packets to the gateway 192.168.1.1. The gateway will change the destination from 192.168.100.100 to 192.168.1.100 and forward the packet to the server at 192.168.1.100.

But this is not enough for the transfer to work. Pinging the 192.168.100.100 result in a timeout. This is the result of DNAT not changing the source of the packets.

When the server receives the request, it will send the response packets to where the request is from, in this example is 192.168.1.114.

The server will notice that the destination of the response packet is on the same LAN, thus the server will not send the packet to the gateway. Instead, it will use ARP to get 192.168.1.114’s mac address and send the packet to 192.168.1.114 directly. The gateway has nothing to do with this process.

The 192.168.1.114 then received the server’s response, but the source of this packet is 192.168.1.100, while the client is expecting a response from the source that the request is sent to, which is the gateway 192.168.1.1(The request to 192.168.100.100 is handled by gateway, so the response should come back from the gateway as well). The client will drop the response because it is invalid.

The SNAT can help the response packet reach its destination correctly.

SNAT

Add this iptables to the router:

1
iptables -t nat -I POSTROUTING -s 192.168.1.0/24 -d 192.168.1.100 -m conntrack --ctstate DNAT -j SNAT --to-source 192.168.1.1

The rules in POSTROUTING chain will be executed after the PREROUTING chain, this will match all previous DNAT packet. Note the destination is 192.168.1.100 after DNAT. The rule changes the source of the packet to 192.168.1.1 (gateway). This also leaves a record in the router so that when the server sends the response to the router, it will be routed to 192.168.1.114.

Now when the server received the request, the source of the request is 192.168.1.1, thus its response will not directly send to 192.168.1.114, instead, the packet is sent to the gateway and then forward to 192.168.1.114 by the gateway.

The client will receive the response with source 192.168.1.1, this is a valid response. Now we can ping 192.168.100.100 from any host in 192.168.1.0/24 without problem.

Misc.

When trying to apply SNAT to my OpenWrt router, an error occurred. According to Status > Firewall statistics, the DNAT works properly but there’s no traffic of SNAT. The bug is fixed by updating to the latest OpenWrt snapshot.


EOF