I have a Linux gateway performing NAT for my home network. I have another network which I'd like to transparently forward packets to, but only to/from specific IP/ports (ie. not a VPN). Here's some example IP and ports to work with:
Source Router Remote Gateway Remote Target 192.168.1.10 -> 192.168.1.1 -> 220.127.116.11 -> 192.168.50.50:5000
I'd like the Source machine to be able to talk to specific ports on Remote Target as if it were directly routable from Router. On the Router, eth0 is the private network and eth1 is internet-facing. Remote Gateway is another Linux machine which I can ssh into and it can route directly to Remote Target.
My attempt at a simple solution is to set up ssh port forwarding on Router, such as:
ssh -L 5000:192.168.50.50:5000 18.104.22.168
This works fine for Router, which can now connect locally to port 5000. So "telnet localhost 5000" will be connected to 192.168.50.50:5000 as expected.
Now I want to redirect traffic from Source and funnel through the now-established ssh tunnel. I attempted a NAT rule for this:
iptables -t nat -D PREROUTING -i eth0 -p tcp -s 192.168.1.10 --dport 5000 -d 22.214.171.124 -j DNAT --to-destination 127.0.0.1:5000
and since the Router is already my NAT gateway, it already has the needed postrouting rule:
-A POSTROUTING -s 192.168.1.0/24 -o eth1 -j MASQUERADE
Most Q&A on this site or elsewhere seem to deal with forwarding server ports or hairpin NAT, both of which I have working fine elsewhere, neither of which apply to this situation. I certainly could DMZ forward Remote Target ports through Remote Gateway, but I don't want the ports internet-accessible, I want them accessible only through the secure SSH tunnel.
The best answer I can find relates to Martian packet rejection in the Linux kernel:
I've enabled logging of martians and confirmed that the kernel is rejecting these packets as martians. Except that they aren't: I know exactly what these packets are for, where they're from and where they're going (my ssh tunnel).
The "roundabout" solution presented there is applicable to that original question, but does not apply for my case.
However, while writing/researching this question, I have worked around my problem by using SSH source IP binding like so:
ssh -L 192.168.1.1:5000:192.168.50.50:5000 126.96.36.199 iptables -t nat -D PREROUTING -i eth0 -p tcp -s 192.168.1.10 --dport 5000 -d 188.8.131.52 -j DNAT --to-destination 192.168.1.1:5000
Since I'm not using loopback, this gets around Martian rejection.
I still post the question here for two reasons:
- In hope that someone who is trying to do something similar in the future might find this in their searches and this workaround might help them.
- I still prefer the idea of keeping my ssh port forwards connection bound only to loopback and being able to route to them through iptables. Since I know exactly what these packets are and where they are going, shouldn't there some way for me to flag them as such so that Linux martian filtering doesn't reject them? All my searching on this topic leads to rp_filter, which didn't help at all in my testing. And even if it did work, it isn't specific to the exact packets I am trying to allow.
I'm interested in contributing my question and workaround to general search to save someone else the hours of searching I did only to come up with dead ends, as well as hopefully having someone answer the loopback/martian part of my question that still remains open to me.