4.3.10 · D3Computer Networks

Worked examples — NAT — why, how, types (SNAT, DNAT, PAT)

3,323 words15 min readBack to topic

Before we compute anything, let us pin down the objects every example uses: the 4-tuple, the protocol, and the notebook.


The scenario matrix

Here is the full space of cases NAT can throw at us. Every cell gets covered by an example below.

# Case class What makes it distinct Covered by
A SNAT, single host One inside host leaves; only IP rewritten Ex 1
B PAT, port collision Two inside hosts, same inside port → must remux ports Ex 2
C DNAT / port forward Outsider initiates inbound → destination rewritten Ex 3
D Degenerate: same inside port AND same peer Worst case for PAT uniqueness Ex 4
E Limiting value: port exhaustion How many flows fit? boundary of the port space Ex 5
F Zero/edge: reply with no matching row Unsolicited inbound packet → dropped Ex 6
G Real-world word problem Office of users, count public IPs needed Ex 7
H Exam twist: NAT breaks the payload IP embedded inside data (FTP/SIP) Ex 8
I Subnet-math cross-check How many hosts a private block holds Ex 9

Example 1 — Cell A: SNAT, one host leaving

Step 1 — Write the packet as it leaves the laptop. Why this step? We must see the before state to know what to rewrite.

Step 2 — SNAT rewrites only the source IP. Private 192.168.0.10 is not routable on the public internet (it's an RFC 1918 address), so the router swaps it for its public IP 203.0.113.5: Why this step? SNAT = "change who it's from." Only src IP moves; the port is untouched because with one host there is no collision to resolve.

Step 3 — Record the notebook row so the reply can be reversed:

Inside tuple Rewritten src Peer
192.168.0.10:51000 203.0.113.5:51000 93.184.216.34:80

Why this step? The outbound packet is now gone; without writing down who 203.0.113.5:51000 really is, NAT would have no way to steer the reply back to laptop .10. The row is the memory that makes reversal possible.

Step 4 — Reply returns. Server sends back . NAT matches the row and restores dst IP → 192.168.0.10.

Verify: Exactly 1 of the four fields changed (src IP). Src port unchanged → 51000 == 51000. ✓ Sanity: with a single host, IP-only SNAT is sufficient — there is nothing to collide with.


Example 2 — Cell B: PAT, two hosts with the same inside port

Figure — NAT — why, how, types (SNAT, DNAT, PAT)
Figure walkthrough: the two violet boxes on the left are the laptops; both fire an arrow labelled 51000 into the orange NAT router — that shared label is the whole problem. On the right of the router, two magenta arrows leave carrying 40001 and 40002: NAT has stamped each flow with a different public port. Trace one violet arrow through the router to its magenta twin and confirm the inside port stayed 51000 but the public port changed — that stamping is what keeps the two flows tellable-apart.

Step 1 — Rewrite IP only, see the clash. Both become: Why this step? To expose the failure: the two flows are now byte-for-byte identical. When a reply arrives, NAT cannot tell whether it belongs to laptop .10 or .11. The notebook would have two rows with the same rewritten source — an ambiguous key.

Step 2 — PAT fixes it by rewriting the source port too. Give each flow a unique public port:

Inside tuple Rewritten src Peer
192.168.0.10:51000 203.0.113.5:40001 93.184.216.34:80
192.168.0.11:51000 203.0.113.5:40002 93.184.216.34:80

Why this step? The table key is now the rewritten source 203.0.113.5:port. Different ports ⇒ different keys ⇒ replies are unambiguous. As the figure shows, the two flows enter with the same port and leave through different public ports.

Step 3 — Reverse a reply. A reply to 203.0.113.5:40002 → notebook says that's 192.168.0.11:51000. NAT rewrites dst back and delivers to .11.

Verify: The two rewritten sources differ (40001 ≠ 40002), so each is a unique key. ✓ This is exactly the parent note's PAT table — we reconstructed it and explained why the port must move.


Example 3 — Cell C: DNAT (port forwarding), outsider initiates

Figure — NAT — why, how, types (SNAT, DNAT, PAT)
Figure walkthrough: read left to right. The navy box is the outsider; its magenta arrow into the orange router still carries the public destination 203.0.113.5:80 — that is all the outsider knows. Inside the router the destination is swapped, and the violet arrow leaving toward the right box now points at the private server 192.168.0.20:80. Notice the source (198.51.100.7:62000) never appears on the arrows as changed — DNAT touches the destination only.

Step 1 — Packet arrives at the router. Why this step? The outsider only knows the public address; it has never heard of 192.168.0.20.

Step 2 — DNAT rewrites the destination. A pre-configured port-forward rule ("public :80192.168.0.20:80", see Port Forwarding & DMZ) rewrites dst: Why this step? DNAT = "change who it's to." Inbound traffic must be steered to the private server; the source is left alone so the server can reply to the real outsider.

Step 3 — The server replies; trace the reverse rewrite. The server sends On the way out NAT must undo Step 2 in reverse: it rewrites the source from the private 192.168.0.20:80 back to the public 203.0.113.5:80, giving Why this step? The outsider addressed 203.0.113.5:80 and knows nothing of 192.168.0.20. If the reply arrived with a private source, the outsider's OS would reject it as belonging to a different conversation. Rewriting the source back makes the outsider see one consistent peer, 203.0.113.5:80, both directions.

Verify: Forward path changed the dst IP (203.0.113.5 → 192.168.0.20); reverse path changed the src IP back (192.168.0.20 → 203.0.113.5). Source of the outsider untouched throughout. Contrast with Ex 1 where SNAT changed src IP on the way out. Two different tools for two different directions. ✓


Example 4 — Cell D: degenerate — same inside port and same peer

Step 1 — List all five fields of each flow's outside view under IP-only rewrite. Both would be a total collision on all five fields. Why this step? Show that the peer dimension and the protocol dimension give no help here — they are identical — so only the source port is still free to change.

Step 2 — PAT assigns distinct source ports. .10 → 40001, .11 → 40002. Now the outside 5-tuples differ in exactly one coordinate — the source port — and that is enough. Why this step? Uniqueness needs the full 5-tuple to differ in at least one field. Source port is the only lever PAT controls here, so it must produce a fresh one.

Verify: After PAT the two outside 5-tuples are (TCP,...,40001,...) and (TCP,...,40002,...) — differ in 1 field ⇒ distinguishable. ✓ Even the worst-case collision is solvable as long as free source ports remain — which motivates Example 5.


Example 5 — Cell E: limiting value — port exhaustion

Step 1 — Count the port space. A port is a 16-bit number, so there are Why this step? Each concurrent flow to the same peer needs its own distinct source port; the count of usable ports is the hard ceiling.

Step 2 — Subtract reserved ports. Port 0 is reserved and the well-known range 1–1023 is normally not used as ephemeral source ports, leaving roughly Why this step? Real routers draw source ports from the ephemeral range, so the practical limit is "about 64000," matching the parent note's figure.

Verify: ; usable . Order of magnitude "~64000" ✓. Note: this limit is per (public IP, peer IP:port, protocol) — different peers or a different protocol reuse the same source ports, so real capacity is far larger.


Example 6 — Cell F: zero case — unsolicited inbound, no matching row

Step 1 — NAT searches the notebook for a row whose rewritten source matches 203.0.113.5:40001 and whose peer matches the packet's source 198.51.100.9:5000. There is none. Why this step? The reverse lookup is the only way NAT knows which inside host a packet belongs to.

Step 2 — No row ⇒ no inside address to write. NAT drops the packet (unless a static DNAT/port-forward rule exists). Why this step? NAT cannot invent a destination. The absence of a row is the "zero" input — the degenerate case where translation is undefined.

Verify: The only row containing 40001 was created in Ex 2 and pairs it with peer 93.184.216.34:80, not 198.51.100.9:5000. Peer mismatch ⇒ no match ⇒ dropped. ✓ This "implicit dropping" is exactly why NAT feels like a firewall — but the parent note warns it is a side effect, not a security policy. See Firewalls vs NAT.


Example 7 — Cell G: real-world word problem

Step 1 — (a) Plain SNAT. IP-only SNAT maps each private IP to a public IP 1:1. 600 devices ⇒ 600 public IPs needed. We have 1. Fails. Why this step? Establishes the naive approach is impossible, motivating PAT.

Step 2 — (b) PAT. Flows are distinguished by source port. From Ex 5, ~64000 concurrent flows fit per peer per protocol; across many different websites the capacity is effectively enormous. 600 devices browsing many sites is trivially handled by 1 public IP. Works. Why this step? Connects the capacity number to the human count.

Step 3 — (c) Dedicated inbound servers. Inbound needs DNAT rules, and each public port can forward to only one inside host. With 1 public IP you have ~64000 ports but a given well-known port (say :443) can forward to only one server. So 600 distinct public-facing HTTPS servers on one IP is not possible on the same port — you'd need more public IPs or a reverse proxy. Why this step? Distinguishes outbound (PAT, many:1, easy) from inbound (DNAT, port-limited).

Verify: (a) needs public IPs ⇒ fails. (b) ⇒ succeeds. (c) one port maps to one host ⇒ constrained. ✓


Example 8 — Cell H: exam twist — NAT breaks the payload

Step 1 — Outbound header is rewritten correctly. src IP 192.168.0.10 → 203.0.113.5. Good. Why this step? Confirms the header path works as in Ex 1.

Step 2 — The payload is NOT rewritten. The body still says "connect back to 192.168.0.10:20500." The server obediently tries to reach a private address it can never route to. The data connection fails. Why this step? Reveals the core defect: NAT only touches the four header fields, not application data embedded in the body.

Step 3 — The fix: an ALG. An Application-Layer Gateway is NAT extended to read the FTP body, spot the embedded 192.168.0.10:20500, and rewrite that string to 203.0.113.5:<mapped port> — the same substitution NAT already does in the header, now applied to the body too. Why this step? The failure in Step 2 was that the header and the body disagreed (header said 203.0.113.5, body still said 192.168.0.10). The ALG restores agreement by patching the body, so the server is told a routable callback address. Peer-to-peer apps that can't rely on an ALG instead use STUN/TURN hole-punching to discover their own public address.

Verify: Without an ALG: header src rewritten (.10 → 203.0.113.5) but payload string unchanged (still 192.168.0.10) ⇒ callback target unroutable ⇒ failure. With an ALG the body is patched to 203.0.113.5 ⇒ header and body agree ⇒ success. ✓ This is a known NAT limitation, not an error in our tracing.


Example 9 — Cell I: subnet-math cross-check

Step 1 — Host bits = . An IPv4 address is 32 bits. A /n fixes ; the rest vary. Why this step? The number of addresses is , so we first need the count of free bits.

Step 2 — Plug each prefix: Why this step? Each fixed prefix leaves exactly the shown number of free bits; raising 2 to that power counts every distinct address the block can hold.

Verify: , , . ✓ Matches the parent note exactly.


Recall Which cell was hardest and why?

Cell D (Ex 4) — total collision on all five fields with the same peer and protocol ::: it forces you to realize PAT's only free lever is the source port, and Ex 5 shows that lever runs out at ~64000 per peer.


Connections

  • 4.3.10 NAT — why, how, types (SNAT, DNAT, PAT) (Hinglish) — parent topic
  • IPv4 Addressing & Subnetting — the /8 /12 /16 host-count math (Ex 9)
  • RFC 1918 Private Addresses — why inside IPs are rewritten
  • Ports & TCP-UDP Headers — the 16-bit port space (Ex 5)
  • Firewalls vs NAT — the "dropped unsolicited packet" side effect (Ex 6)
  • STUN, TURN & NAT Traversal — fixing the payload problem (Ex 8)
  • Port Forwarding & DMZ — DNAT rules (Ex 3)
  • IPv6 — abundant addresses remove the need for PAT