Firewall NAT Rules: SNAT vs DNAT with Real Examples

Network Address Translation rewrites packet fields so flows can cross boundaries, but whether you change the source (SNAT) or the destination (DNAT) determines routing, policy, and how replies find their way back.
When users browse out to the internet you need SNAT so return traffic comes back to your gateway; when outsiders reach services you host, you need DNAT so a public address forwards to a private server. Mixing them without a clear model leads to half-open sessions, hairpin failures, and head-scratching logs.
We’ll align the mental model with how common stacks behave (Linux iptables/nftables and popular firewall vendors), walk through real topologies, and point out failure signatures you can recognize quickly.
SNAT vs DNAT: Clear Definitions and Flow
SNAT changes the source address and often the source port on egress so replies target the translating gateway; DNAT changes the destination address (and sometimes port) on ingress so outside clients can reach internal services. Both rely on a state entry keyed by a 5-tuple and reversed on the way back.
Where Translation Happens (by Stack)
On Linux routers (iptables/nftables), DNAT is applied before routing (PREROUTING), then the packet is routed, filtered, and finally SNAT happens as the packet leaves (POSTROUTING). On several vendor firewalls, NAT policy is evaluated early in session setup, but security policy commonly matches pre-NAT IPs while zone/egress may be post-NAT; translation itself is finalized at egress. Always check your platform’s rule-match semantics.
What the Server and Client See
With DNAT, your internal server still sees the real client source IP, which is helpful for logging and ACLs; with SNAT, the outside world sees the firewall’s public IP. If a reverse proxy sits in front, the hop from proxy to app may hide the client unless you pass it (for example with X-Forwarded-For) or use a proxy protocol.
Real Example 1: Outbound Internet with SNAT (Many-to-One)
Topology: 10.0.10.0/24 inside; firewall WAN 203.0.113.10. Configure SNAT/PAT on the WAN. A client 10.0.10.25:51500 to 198.51.100.20:443 becomes 203.0.113.10:55001 to 198.51.100.20:443. The state table maps the original tuple to the translated one so replies arriving at 203.0.113.10:55001 get de-translated back to 10.0.10.25:51500.
Gotchas in Outbound SNAT
Port exhaustion appears when many short-lived connections share a single public IP. Mitigations: use a PAT pool (multiple public IPs), reduce needless connection churn at the app/HTTP layer, and tune session timeouts carefully (shorter for idle UDP, conservative for established TCP). Monitor active translations versus ephemeral port availability per egress IP.
How to Validate Egress
From a client, open an external TCP connection and compare the observed source IP to the expected SNAT address; on the gateway, confirm live state entries and incrementing counters. If multi-WAN exists, ensure policy routes or SNAT rules are interface-scoped so replies come back on the correct link.
Real Example 2: Inbound Web with DNAT (Port Forward)
Topology: Public 203.0.113.10:443 forwards to internal 10.0.10.10:443. The firewall performs DNAT on ingress, routes to the server, and installs state. The server’s default gateway must be the same firewall (or policy-routed back to it) so the reply matches the DNAT state and is un-translated to the internet client.
Inbound Gotchas
Asymmetric return is the classic failure: the server replies via another router or uplink, bypassing the stateful device that did DNAT. Fix by making the DNAT firewall the server’s default gateway or by policy-routing replies to it. Also note that many platforms evaluate security policy against pre-NAT addresses; write the allow rule accordingly and verify which zones are considered before/after NAT.
One Public IP, Many Services
Map distinct public ports to different internal hosts (for example, 203.0.113.10:80 → 10.0.10.20:8080, 203.0.113.10:22 → 10.0.10.30:22). Be explicit about TCP vs UDP and know their different idle timers.
Hairpin NAT (Loopback) for Internal Clients Using the Public Name
Problem: Inside users connect to a public FQDN resolving to your public VIP, but the service lives on 10.0.10.10. Without hairpin, the server may try to reply directly to the client on the LAN, bypassing the firewall’s state and breaking the flow.
Typical fix on general routers: combine DNAT to the server with an SNAT to the firewall’s inside address for traffic sourced inside and destined to the public VIP. That forces the server to reply to the firewall, which reverses both translations cleanly. Some firewalls offer “NAT reflection” features or recommend split-DNS; pick the method your platform supports reliably.
Order of Operations and Policy Matching
Two common models exist. Linux pipeline: DNAT (pre-routing) → route decision → filter/policy (post-DNAT addresses) → SNAT (post-routing). Many vendor firewalls: NAT policy evaluation occurs during session setup; security policy usually matches pre-NAT addresses but may use post-NAT zones; translation is applied at egress. Read your platform’s packet-flow guide so your rules reference the addresses the engine actually matches.
State, Timeouts, and Ephemeral Ports
NAT is stateful: the first packet creates a mapping in the connection-tracking table keyed by protocol, source/destination IP, and ports. Idle and handshake timeouts differ by protocol and state (SYN-sent vs established, UDP short vs active). Ephemeral source ports come from OS-specific ranges: IANA defines 49152–65535 as the dynamic range; Windows uses that by default; many Linux distributions default to 32768–60999 (configurable via sysctl). Capacity planning for PAT must account for per-IP ephemeral pool size and 5-tuple uniqueness, not just port count.
Dual WAN and Symmetry
With two uplinks, tie SNAT to the egress interface so return traffic follows the path that created state. For inbound DNAT, either publish on one ISP only or enforce symmetric egress for server replies (policy routing/PBR). If your firewall supports VIP monitoring, withdraw the public mapping on failure to avoid blackholing new sessions.
Reverse Proxies and Preserving Client IP
Putting a reverse proxy in front of apps keeps real client IPs at the proxy. Between the proxy and app, decide whether to SNAT (simpler but hides the client) or to pass the client IP in headers or via a proxy protocol the app understands. Validate what your app stack logs and trusts before you change anything.
NAT with FTP, SIP, and Other “Embedded Address” Protocols
Protocols that carry IP:port details in payload (FTP, SIP/RTP, some VPNs) can fail unless helpers/ALGs or aware proxies rewrite those fields to match the NAT mapping. When possible, terminate them on a proxy or SBC rather than relying purely on generic ALGs, and constrain dynamic port ranges so firewall rules stay predictable.
Simple, Reliable Tests
SNAT: from an inside host, connect to a known internet service and confirm the observed public IP matches your egress rule; watch the firewall’s translation/session counters. DNAT: from an external vantage point, connect to the public IP:port while you tail the session/NAT table; the server should see the real client source and replies must traverse the same firewall. Hairpin: from inside, use the public FQDN and confirm the firewall both DNATs the destination and SNATs the source to its inside address.
Troubleshooting Checklist
Verify the server’s default gateway or policy route, confirm which address (pre- or post-NAT) your platform matches in security policy, ensure multi-WAN symmetry, check NAT state for collisions/port pressure, and for tricky protocols validate whether a helper or proxy is in play.
Pocket Map
SNAT = change source on egress to anchor replies; DNAT = change destination on ingress to publish internal services; hairpin = DNAT + SNAT for inside users calling the public VIP; Linux filter sees post-DNAT addresses; several vendor firewalls evaluate NAT early but match security on pre-NAT IPs; watch port ranges and state timeouts; breakages usually trace to asymmetric return, wrong policy match address, or ephemeral-port pressure.