Linux iptables – Tighten Forward Chain for DNAT and SNAT Traffic

iptableslinuxport-forwarding

I want my linux router/internet gateway 192.168.80.1 to forward port 9091 to 192.168.80.15:9091 when requested via LAN. I also want my router to forward WAN-originating requests on port 9091 to 192.168.80.15:9091.

The second part I have completed successfully and I am most of the way there with the first part using

iptables -A PREROUTING -p tcp -m tcp --dport 9091 -j DNAT --to-destination 192.168.80.15:9091
iptables -A POSTROUTING -d 192.168.80.15/32 -p tcp -m tcp --dport 9091 -j SNAT --to-source 192.168.80.1

as per the top answer here. However this only works if I set the FORWARD policy to ACCEPT. I would like to keep the forward policy as DROP and create a specific exception for the traffic I'm forwarding.

I've tried

iptables -A FORWARD -p tcp --dport 9091 -j ACCEPT

and it passes traffic to 192.168.80.15:9091 but the response from 192.168.80.15 to 192.168.80.1 comes back on a different port and I think is getting dropped. How can I craft a rule which keeps things relatively secure while allowing my desired traffic? I've played with conntrack but had no success so far.

UPDATE:

I understand there's an alternative approach called a hairpin NAT. I'm open to arguments if this is a better approach but I should note that currently bind is configured on my gateway/router such that my domain name resolves to 192.168.80.1 for clients on my LAN (whereas it resolves to the gateway's public IP externally)

Ultimately I want mydomain.com:9091 to access the same service regardless of the request originating from LAN or WAN.

Best Answer

The packets must pass through your router, so they must pass the FORWARD chain.

An easy way to achieve that is to use this command:

iptables -A FORWARD -m conntrack --ctstate ESTABLISHED -j ACCEPT

Connection tracking is needed anyway for NAT (SNAT or DNAT) to work, so it doesn't even add much overhead, and you don't have to worry about specific rules.

Related Topic