i would like to forward a ssh port to another host and a different port and interface.

server1:22 -> server1:22

public internet -> eth0 -> server1:23 -> eth1 -> server2:22

i enabled ipv4 forwarding

sysctl -p
net.ipv4.ip_forward = 1

and created the following ip table rules

iptables -t nat -I PREROUTING -p tcp -i eth0 --dport 23 -j DNAT --to-destination
iptables -A FORWARD -i eth0 -o eth0 -p tcp --dport 23 -j ACCEPT

but i can't get it to work, what am i missing?

finaly with haukes help i got it to work

iptables -t mangle -A PREROUTING -d <Server1_eth0> -p tcp --dport 2223 -j MARK --set-mark 1 -i eth0
iptables -t nat -A PREROUTING -p tcp -m mark --mark 1 -j DNAT --to-destination <Server2>:2222 -i eth0
iptables -t nat -A POSTROUTING -m mark  --mark 1 -j SNAT --to-source <Server1_eth1> -o eth1 
iptables -A FORWARD -m mark --mark 1 -j ACCEPT -o eth1

where Server1_eth0 is my public ip

If server1 is not the gateway for server2 then you need SNAT, too. Otherwise server2 will send the reply to the client which doesn't recognize the packet as it doesn't have server1 as source address but server2.

iptables -t nat -A POSTROUTING -p tcp -m conntrack --ctstate DNAT --ctorigdst server1 --ctorigdstport 23 -j SNAT --to-source server1

A precise and easy to understand filter criteria for the rules in FORWARD, PREROUTING and POSTROUTING would be a packet mark:

iptables -t mangle -A PREROUTING -d $server1_ip -p tcp --dport 23 -j MARK --set-mark 22
iptables -t nat -A PREROUTING -p tcp -m mark --mark 22 -j DNAT --to-destination $server2_ip:22
iptables -t nat -A POSTROUTING -m mark --mark 22 -j SNAT --to-source $server1_ip
iptables -A FORWARD -m mark --mark 22 -j ACCEPT

Please note: If server1 has more than one interface and the DNATed packets are routed from one interface to another (like it turned out in this case) then the destination match IP and the SNAT IP are different.

"-p tcp" should not be necessary in the second line but iptables or Netfilter requires it. It may be useful to add e.g. -m comment --comment "DNAT SSH from port 23 to server2" in all lines to make the optput of iptables -L -nv easier to understand.

  • so i should add this to the other 2 rules i've already got? do i have to set --ctorigdst ? – supernova Feb 27 '13 at 0:53
  • Sure you have to add this. The command does what's needed in less complex variants. Ijust felt like looking up how to do it "the right way". iptables -t nat -A POSTROUTING \! -d server2 -j SNAT --to-source server1 would do the same but may (depending on the circumstances) match more packets than the DNATed ones for SSH. That can be a problem but is not necessarily one. I have an idea for a clearer solution, I'll edit my answer. – Hauke Laging Feb 27 '13 at 1:07
  • i added "iptables -t nat -A POSTROUTING -p tcp -m conntrack --ctstate DNAT --ctorigdst --ctorigdstport 23 -j SNAT --to-source" to the 2 rules which i posted above and also tried to-source but haven't had any success so far. – supernova Feb 27 '13 at 1:15
  • Have a look at the traffic with tcpdump. What is the problem, does the SNAT rule not match? – Hauke Laging Feb 27 '13 at 1:30
  • sorry i forget to mention that i have 2 interfaces, traffic comes in at eth0 and should leave at eth1, since eth0 is connected to the internet and eth1 is connected to a private network. at the first two rules i added -i eth0 and at the last two i added -o eth1, if i listen with tcpdump -i eth1 dst where the ssh connection should be routed to i get ARP, Request who-has a1c tell a1f - i edited my question. – supernova Feb 27 '13 at 14:02

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.