Turn a host into a router with NAT

applied · 45 min · Objective 3.2

Task

Configure a Linux host to route and masquerade for a private network, forward one inbound port to an internal service, and prove each piece works. Then find the setting whose absence makes all the firewall rules irrelevant.

Steps

  1. Give the router an address on the private side and the client a default route through it. Confirm they can ping each other.
  2. From the client, try to reach an external address. It fails. Before changing anything, predict which of routing, NAT or firewall is missing.
  3. Enable forwarding temporarily with sysctl -w net.ipv4.ip_forward=1 and retry. Note that it still may not work, and why.
  4. Add masquerading on the external zone: firewall-cmd --zone=public --add-masquerade --permanent and reload. Confirm the client can now reach the internet, and confirm with tcpdump on the router that the source address is being rewritten.
  5. Make forwarding persistent in /etc/sysctl.d/, reboot, and confirm it survived -- the sysctl -w from step 3 did not.
  6. Forward an inbound port to the client's web server: firewall-cmd --permanent --add-forward-port=port=8080:proto=tcp:toport=80:toaddr=10.10.0.20. Test from outside.
  7. Explain, in terms of PREROUTING and POSTROUTING, which of the two rules you added rewrites the destination and which rewrites the source.

Verify

sysctl net.ipv4.ip_forward                        # 1, after reboot
firewall-cmd --list-all --zone=public | grep -E 'masquerade|forward-port'
# from the client:
curl -sf -o /dev/null -w '%{http_code}\n' http://example.com/
# from outside, against the router:
curl -sf -o /dev/null -w '%{http_code}\n' http://<router-external-ip>:8080/

All four must succeed after a reboot. The reboot is not optional: it is what distinguishes a router you configured from one that merely works until it restarts.

Notes

Step 3 is the point of the lab. With forwarding off, the kernel silently drops every packet not addressed to itself, and no amount of correct firewall configuration changes that. It is the first thing to check when a Linux router passes nothing, and the last thing most people think of.