Octet

Inside users cannot reach an internal server by its public address, but internet users can. Why, and how do you fix it?

Show the answer

Say this first

That is NAT hairpinning, also called NAT loopback or reflection. The user's packet to 203.0.113.5 enters R1 on an inside interface, and IOS only translates a global destination back to the local one for packets that arrive on an outside interface, so nothing rewrites it. Even on devices that do rewrite it, a server on the same subnet as the user replies straight to the user from its private address, and the user drops that reply. The clean fix is split DNS. If you must hairpin, the device has to translate both destination and source.

Go deeper

Why it fails

  1. PC1 (192.168.10.10) resolves app.example.com to 203.0.113.5 and sends a SYN to it.
  2. The SYN enters R1 on Gi0/0/1, an inside interface. Outside-to-inside translation only applies to packets arriving on an outside interface, so the destination stays 203.0.113.5 and the packet never reaches SRV1 at 192.168.20.10.

The same-subnet trap

Suppose a device does rewrite the destination (Linux DNAT applies on any interface). If the client sits on the server's own subnet, the server replies directly from 192.168.20.10. The client sent its SYN to 203.0.113.5, so it discards the reply. The device has to rewrite the source as well, so the reply comes back through it.

Fixes, best first

  1. Split DNS: the internal view of app.example.com returns 192.168.20.10. No hairpin at all.
  2. A DMZ on its own interface: clients and servers on different interfaces, so replies always return through the edge device.
  3. Hairpin NAT on the edge device. On Linux:
Shell
iptables -t nat -A PREROUTING -d 203.0.113.5 -p tcp --dport 443 -j DNAT --to-destination 192.168.20.10
iptables -t nat -A POSTROUTING -s 192.168.20.0/24 -d 192.168.20.10 -p tcp --dport 443 -j MASQUERADE

The first rule has no -i, so it applies to inside traffic too. The second source-NATs clients on the server's own subnet so their replies return through the router.

On classic IOS the NAT Virtual Interface (ip nat enable on interfaces, ip nat source ... rules without inside or outside) supports hairpinning, but NVI is not supported on IOS-XE.

Traps

  • Testing a new port forward from inside the LAN and declaring it broken.