7

I am trying to use SSH to port forward windows machines local port 3389 to a redhat server on some arbitrary port (in the unprivileged region) I have protected behind a firewall, then forward the unprivileged port on the redhat server onto the users remote desktop. Essentially create a highly specalized VPN which only handles one task: Get users to their systems behind a firewall using an encrypted tunnel I have control over.

I know years ago this was possible using the command:

iptables -A OUTPUT -t nat --dport ${LOCAL UNPRIV PORT} \
           -j DNAT ${ANOTHER SYSTEM}:${REMOTE PORT}

but from what I read, it looks like that ability was removed, and I get the message in /var/log/messages

      kernel: NAT: no longer support implicit source local NAT 

I found resources which suggest that from kernel 2.6.X - 2.6.10, there was a way to enable this in the kernel using IP_NF_NAT_LOCAL, but apparently in more recent kernels its been removed. I have tried forwarding all local traffic so it will enter the PREROUTING chain, and have had limited success, and that just feels like a bad idea, because then I have to open the unprivileged port on the server so I can feed it back into the eth0 interface. I'm sure given more time I could figure out some sort of bizarre kludge, or workaround, but I would rather not hack up my firewall scripts that much. It seems like there must be a much easier way of doing this I'm not seeing. Any help or guidance the community could provide would be very helpful! Thanks in advance

2
  • Why are you trying to forward local traffic? Your question seems to indicate you want to forward certain incoming traffic?
    – Erik
    Mar 12, 2011 at 0:22
  • I'm trying to forward local traffic because when you do ssh -L ${local port}:${remote host}:${remote port} ${remote server} it wont work if you enter remote host as an IP address off the same subnet of the system you are logging in from. So I have entered localhost for the remote system instead. This has the effect that the remote server I'm SSH'ing into thinks that the traffic is being generated locally. Hence whey I am using the OUTPUT routing chain.
    – dynamphorous
    Mar 14, 2011 at 15:30

3 Answers 3

12

I'm not completely sure if I understood, but I think you're just in the wrong chain. :-) I was confused, too, when I used iptables the first time. But the way to forward the local port ${LOCAL UNPRIV PORT} is the statement below:

$IPT -t nat -A PREROUTING -i eth0 -p tcp --dport ${LOCAL UNPRIV PORT} 
     -j DNAT --to ${ANOTHER SYSTEM}:${REMOTE PORT}

It is a mixture between a semantic problem and the way netfilter works: In the old days forwarding a local port involved a connection to the box that is forwarding, plus a second connection to the destination. Iptables does this in one step. So instead of two connections - you are forwarding the traffic to that port directly to the destination. Netfilter does all the sanity checks and bookkeeping: only packets that belong to a valid connection are NATted and can therefore be forwarded.

Enabling DNAT doesn't allow any packets to be forwarded. You also have to add a rule:

$IPT -N INET-PRIV
$IPT -A FORWARD -i eth0 -o eth1 -j INET-PRIV
$IPT -A FORWARD -j DROP

$IPT -A INET-PRIV -p tcp -d ${ANOTHER SYSTEM} --dport ${REMOTE PORT} -j ACCEPT

$IPT -A INET-PRIV -j DROP

And you have to enable forwarding of course.

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

Pro iptables: more secure, more flexible, less memory and CPU used per connection

Contra iptables: forwarding a connection from a internal machine to a internal machine (feed it back into the eth0) doesn't make sense with iptables (of course you can always connect directly), forwarding traffic that is generated locally doesn't work (a port forwarding daemon might help - but usually doesn't make sense)

Exactly this might be the problem: you try to use NAT on a non-router, so you should use a forwarding daemon or skip this extra port forwarding completely and do:

ssh -L 1234:${ANOTHER SYSTEM}:${REMOTE PORT} special-vpn-box

On special-vpn-box you can only allow incoming connections from the router and outgoing connections to ${ANOTHER SYSTEM}:${REMOTE PORT} using iptables. That way users of the special-vpn-box can only access ${ANOTHER SYSTEM}:${REMOTE PORT} and won't be able to do anything else if they aren't trusted.

7
  • I certainly have tried the ssh the way you described, with the automatically forwarding it to the next machine. So basically if the system behind the firewall has an IP of 192.168.0.2, then do ssh -L 3389:192.168.0.2:3389 to special vpn box. But what I'm left with is when you try to connect to 192.168.0.2 3389 it just says "no path to host" when you try telnet. I tried doing the configuration you suggested (which is pretty close to what I already have) but when i check /var/log/messages the packet never hit the PREROUTING rule (when i switch to log vs acept)
    – dynamphorous
    Mar 14, 2011 at 20:19
  • Can you please list your hosts, what you do on what host and how they are connected. I suspect we still don't talk about the same thing.
    – Ganwell
    Mar 15, 2011 at 11:37
  • Firstly Ganwell, thank you very much for your time. I really appreciate your help. Ok, here is my layout. I have a remote user, I will call ${RU}. I have a redhat server with an open ssh port in the firewall directed at it I will call ${RHS}, and a local system behind the firewall I will call ${LS}. I want to have ${RU}-->SSH-->${RHS}-->RDP-->${LS}. To do this I have been using ssh port forwarding to get to the ${RHS}, then trying to DNAT that apparent (to the ${RHS} "local" traffic onto the ${LS} on port 3389 (RDP). Mar 15, 2011 at 15:39
  • I have tried to use output to DNAT the destination back to the address of eth0, then using postrouting to SNAT and also set that to eth0. Then I was going to use the prerouting chain to DNAT them to the correct source. Seems WAY too complex. However the output chain, if I DNAT them directly to the address of the ${LS}, it never hits the postrouting chain (I have tried various logging options, and they definitely never get there). And from my understanding, if they are not making it to the postrouting chain, they are not leaving the system. Mar 15, 2011 at 15:49
  • Ok. I think I got the problem, you are doing DNAT on the ${RHS} System right? You can't DNAT traffic that is generated on the local system. You can DNAT on the firewall, but once you passed the firewall you don't need any port forwarding (DNAT) anymore. You just have to change: ssh -L 3389:192.168.0.2:3389 to ssh -L 3389:${LS}:3389
    – Ganwell
    Mar 15, 2011 at 17:12
8

Here is what I do specifically for localhost forwarding:

iptables -t nat -A OUTPUT -m addrtype --src-type LOCAL --dst-type LOCAL -p tcp --dport 3306 -j DNAT --to-destination ip.ip.ip.ip
iptables -t nat -A POSTROUTING -m addrtype --src-type LOCAL --dst-type UNICAST -j MASQUERADE

sysctl -w net.ipv4.conf.all.route_localnet=1

Make sure you substitute ip.ip.ip.ip for your real public IP and also the --dport 3306 for the port you want to forward.

Finally run the sysctl command and also update your /etc/sysctl.conf

You can update sysctl.ctl to allow the routing of localhost with the following command:

echo "net.ipv4.conf.all.route_localnet=1" >> /etc/sysctl.conf

Now this all seems simple and good but it did take some research and hunting down. Be warned and understand that forwarding localhost/127.0.0.1 requires this method and the typical other examples do not work. Some examples of solutions that do not work with localhost:

iptables -t nat -A PREROUTING -p tcp --dport 3306 -j DNAT --to ip.ip.ip.ip:3306
iptables -t nat -A POSTROUTING -d ip.ip.ip.ip -j MASQUERADE

http://realtechtalk.com/iptables_how_to_forward_localhost_port_to_remote_public_IP-1788-articles

3
  • Tried this one instead of the accepted answer as it seemed less complex and it worked like a charm (Ubuntu 20.04.2 LTS). Jul 6, 2021 at 8:22
  • I totally agree that for localhost all this complexity is required. Tested on Debian Bullseye and it works.
    – famzah
    May 18, 2023 at 8:53
  • net.ipv4.conf.all.route_localnet=1 has SECURITY implications because it could allow external traffic to reach localhost-only services. Here is a PoC: github.com/kubernetes/kubernetes/issues/90259
    – famzah
    May 18, 2023 at 10:42
3
# Enable IP Forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward

iptables -t nat -A PREROUTING  -p tcp \
--dport ${LOCAL UNPRIV PORT} -j DNAT --to-destination ${ANOTHER SYSTEM}:${REMOTE PORT}

iptables -t nat -A POSTROUTING -p tcp \
--dst ${ANOTHER SYSTEM} --dport ${REMOTE PORT} -j SNAT --to-source ${LOCAL SYSTEM}
1
  • This one works for me, thank you !! ... these are the commands I use: iptables -t nat -A PREROUTING -p tcp --dport 6379 -j DNAT --to-destination 127.0.0.1:6379 ; iptables -t nat -A POSTROUTING -p tcp --dst 127.0.0.1 --dport 6379 -j SNAT --to-source 172.27.138.104 Oct 23, 2021 at 16:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .