How do I forward/NAT all traffic to one interface/IP to a remote IP?

Solution 1:

Short answer to your revised question is that there are two ways to do it; both require you remove the second NAT step (which destroys the info you're looking for). Your options after doing that are:

1) Make Server A the next hop for Server B for the traffic in question, which is why it works for your router as mentioned. This could be accomplished, in order of cludgeyness, by making server A the default route for Server B, or using policy routing, or using some fancy iptables, or using a tunnel of some sort.

2) "Manually" reversing server A's NAT on server B, resulting in asymmetric traffic flow (generally discouraged). Something like iptables -t nat -I POSTROUTING -j SNAT -s 2.2.2.3 --to 1.1.1.3

I am 100% confident in option (1). I'm about 90% confident in (2).

To understand this, you need to understand the traffic flow.

  1. Client X sends a packet to 1.1.1.3.
  2. Server A NATs the destination of that packet to 2.2.2.3 pre-routing, then routes the traffic to 2.2.2.3, then NATs the source of that packet to 1.1.1.3 post-routing, then sends the packet to Server B.
  3. Server B receives the packet on 2.2.2.3 and sees a source address of 1.1.1.3, per the second NAT step. It processes the packet and sends the reply back to its source (1.1.1.3).
  4. Server A receives the packet on 1.1.1.3, reverses the source NAT, routes the packet, reverses the destination NAT, and sends the packet back to client X.
  5. Client X receives the response from 1.1.1.3

Now let's imagine what would happen if you didn't have the second NAT:

  1. Client X sends a packet to 1.1.1.3.
  2. Server A NATs the destination of that packet to 2.2.2.3 pre-routing, then routes the traffic to 2.2.2.3, but leaves the source address as X when it sends the packet to Server B.
  3. Server B receives the packet on 2.2.2.3 and sees a source address of X. It processes the packet and sends the reply back to its source X.
  4. Client X receives the response from 2.2.2.3 and discards it because it doesn't know 2.2.2.3 from Adam!

In order for Client X to understand the packet, it needs to arrive at Client X with the same source address as was the destination of the original packet.

The normal way for this to happen is for Server B to have an opportunity to reverse the pre-routing NAT. For that to happen you need the packet to go back through it at a later date. Currently you do that by changing the source address of the packet, but that destroys the information you're asking for in your revised question.

So the first step of your answer is, you can't do the second NAT step (post-routing SNAT): on server A run iptables -t nat -D POSTROUTING -j SNAT --to 1.1.1.3.

Now you're left with the challenge of reversing the first NAT step.

If Server B is going to do it, you need Server B to receive the packets.

  • This is relatively easy if server A has an address C on the same LAN as server B. On server B: ip route replace default via C, OR ip route add default via C table a; ip rule add from 2.2.2.3 table a.
  • Otherwise you have to do something fancy with tunnels.

If, however, the router at Server B's location is not particularly sophisticated (statefully inspecting packets and rejecting ones that are not in correct sequence for a known traffic flow), you have a somewhat simpler, if super-ugly, option: reverse the NAT at server B based on your knowledge of what was done at server A: on server B iptables -t nat -I POSTROUTING -j SNAT -s 2.2.2.3 --to 1.1.1.3 should do it the proposed example. This will leave the Linux connection tracking system at A and B somewhat befuddled (servers will not be able to associate return traffic with incoming traffic so their connection tracking will leave connections in UNREPLIED state) but it should work fine for most traffic into the hundreds of megabits.

Walking through the traffic flow one last time in this case:

  1. Client X sends a packet to 1.1.1.3.
  2. Server A NATs the destination of that packet to 2.2.2.3 pre-routing, then routes the traffic to 2.2.2.3, but leaves the source address as X when it sends the packet to Server B.
  3. Server B receives the packet on 2.2.2.3 and sees a source address of X. It processes the packet and routes the reply back to its source X, but before sending it out does the post-routing NAT of the source adderess to 1.1.1.3.
  4. Client X receives the response claiming to be from 1.1.1.3 and is happy.