Using iptables to proxy a port on a remote machine on a different network

By thomas, 11 December, 2013

Scenario

machine A (192.168.100.1) provides resource A on port 8888
machine B (192.168.200.1) needs to access resource A

without modifying machine B (not allowed), create machine C and have any traffic to machine C on port 8888 forwarded to machine A. Then tell machine B that machine C is machine A and nobody is the wiser. None of the examples I found online had this working properly.

I eventually came up with the following.
machine C has two interfaces:
one that is on the same network as machine B - 192.168.200.2 eth0
one that is on the same network as machine A - eth1


*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [4698:1663560]
-A FORWARD -i eth0 -o eth1 -p tcp -m tcp --dport 8888 -j ACCEPT
-A FORWARD -i eth1 -o eth0 -m state --state ESTABLISHED -j ACCEPT
-A FORWARD -j DROP
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [28:2328]
:OUTPUT ACCEPT [831:65096]
-A PREROUTING -d 192.168.200.2 -p tcp -m tcp --dport 8888 -J dnat --TO-DESTINATION 192.168.100.1:8888
-a postrouting -o eth1 -j MASQUERADE
COMMIT

So we allow from eth0 to eth1 on port 8888 with the forward rule which then passes to the nat table for masquerading. The thing that most blogs are missing is the reverse connection from eth1 to eth0 with the established traffic. Without that you can connect and send data but nothing ever comes back. You have to enable ip_filter with sysctl as usual. You might need to enable rp_filter, but I didn't.