What I have:

I have 2 linux based gateways/routers that connect 3 networks:

NET-A <=> gwAB <=> NET-B <=> gwBC <=> NET-C

For specific limitations w.r.t routing it is not possible to access NET-C via Layer3 IP/Routing with a source IP address from a Host from NET-A. (Because hosts in NET-C are multi-homed and normal routing is not via gwBC)

What I am trying to do:

In order to access hosts in NET-C from NET-A via gwAB and gwBC I am trying to do source NAT combined with port forwarding happening on gwBC. More specifically I am trying do ssh to arbitrary hosts in NET-C via gwBC on specific non-standard port (e.g. 10022) which is then forwarded to port 22 with the original (NET-C) destination address (based on destination port 10022)

Let's assume the following subnets:
... and hosts:
hosts in NET-A: (gwAB) (source)
hosts in NET-B: (gwAB) (gwBC) hosts in NET-C: (gwBC) (destination)
... and routing:
gwAB: via gwBC (
gwBC: via gwAB (
destination: via gwBC, via gwXY

ssh from to

  1. the source IP of should be rewritten as (gwBC) (if packets destination ip is within net:
  2. the destinataion Port should be set to 22 (if packets dest ip is within net:

In Summary the following NAT should happen in order to produce the desired routing to/from destination host
|SrcIP--:Port|-----DstIP----:Port---| => |--SrcIP---:Port|--DstIP-----:Port|
| | | => | | |

is it possible (and how) to do this using iptables ? I already tried extension REDIRECT in order to change port. But as I found it only redirects traffic to the machine itself. I also tried extension DNAT. But as I found it is only possible to specify a single new destination IP address/Port. This is not exactly what I want, because I only want to change the port but not the destination.

Edit 1 (17/09/18 22:30 MEZ): major edit of the entire post done, based on response of Arlion


Please update your post with your default gateway, or a copy of your current route table translated and sanitized into your post. I will be writing this as if you had another default gateway specified.

Enable port forwarding:

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

Write Static Routes for where the traffic will be going:

I can't help you on this point b/c your post is a bit unclear in this part.

hosts in NET-A: (gw) (source) Sounds like to me

ip route add via dev NET-A
iptables -t nat -A POSTROUTING -o NET-A -j MASQUERADE

hosts in NET-B:, (gw)

I think this is a mistake due to a routing conflict here. 
This assumes that the same subnet and lives in two separate locations. 
This would be a fatal flaw in network topology. 
If we wanted to work around this, this would be
ip route add via dev NET-B
iptables -t nat -A POSTROUTING -o NET-B -j MASQUERADE

hosts in NET-C:, (gw) (destination)

 ip route add via dev NET-C
 ip route add via dev NET-C
 iptables -t nat -A POSTROUTING -o NET-C -j MASQUERADE

Masquerede NAT forwarding takes all the incoming traffic, and replaces the TCP header with it's own IP and forwards the packet as if it was itself.

As for the final part: Anything that comes in on NET-A on port 10022 will be port forwarded to

iptables -A PREROUTING -t nat -i NET-A -p tcp --dport 10022 -j DNAT --to
  • I updated the question, in the hope to more proper describe the problem. – user1240076 Sep 17 '18 at 20:47

I solved the problem by adding an iptables jump target SNAT.

As per the example the following NAT rule on gwBC has been created (in the end I just use port 22, which is obviously more convenient for users):
iptables -t nat -A POSTROUTING -d -p tcp --dport 22 -j SNAT --to-source

Explanation: the source address is translated for all destinations: by gwBC (NET-C interface): With this source address standard routing can be applied.

Edit 1: solution simpliefied. No additional host route necessary.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.