IPv6 and NAT

In the early 1980s, 2^{32} — 4.3 billion — IPv4 addresses felt like more than the human race could ever need. Then came PCs, then phones, then a fridge with Wi-Fi. By the 2010s the regional registries were literally handing out their last blocks; the free pool ran dry. The Internet faced a genuine arithmetic crisis: more devices than addresses. Two responses emerged, and — fascinatingly — both are still running side by side today. One is a clever, slightly grubby stopgap that stretches the old addresses (NAT); the other is a clean, enormous replacement that ends scarcity forever (IPv6). This page is about both, and about why the "temporary" hack has outlived every prediction of its retirement.

NAT: making one address look like hundreds

Look at your home. A laptop, two phones, a games console, a TV, a doorbell — a dozen devices, each with a private RFC 1918 address like 192.168.1.x. Yet your ISP gave you exactly one public IPv4 address. How do a dozen devices share one public identity? Network Address Translation.

Your home router sits on the boundary. When an inside device opens a connection, the router rewrites the packet: it swaps the private source IP and source port for its own public IP and a freshly chosen port, and records the swap in a NAT translation table. When the reply comes back to that public IP:port, the router looks up the table, rewrites the destination back to the original private IP:port, and delivers it inside. The outside world sees only the router's single public address; the multiplexing across dozens of devices is hidden entirely in that table. Because it rewrites ports as well as addresses, this is often called NAPT (Network Address Port Translation) or "PAT" — and the port is what makes many-to-one sharing possible.

Inside (private) IP:portRouter public IP:portOutside destination
192.168.1.10:52001203.0.113.5:4000193.184.216.34:443
192.168.1.23:52001203.0.113.5:4000293.184.216.34:443
192.168.1.10:52014203.0.113.5:40003142.250.72.14:80

Notice the first two rows: two different inside devices both used source port 52001 and both talked to the same server — a collision that would be ambiguous on the wire. NAT resolves it by giving each a distinct public port (40001 vs 40002), so replies are never confused. The demo below builds exactly this table.

// A minimal NAT (NAPT) box. It rewrites (privateIP, privatePort) to the // router's single public IP with a unique public port, remembers the mapping, // and can translate a reply back to the right inside host. const PUBLIC_IP = "203.0.113.5"; let nextPort = 40001; const table = new Map<string, string>(); // publicKey -> "privIP:privPort" function outbound(privIP: string, privPort: number, dst: string): string { const pubPort = nextPort++; table.set(`${PUBLIC_IP}:${pubPort}`, `${privIP}:${privPort}`); console.log(`OUT ${privIP}:${privPort} -> ${dst} rewritten as ${PUBLIC_IP}:${pubPort}`); return `${PUBLIC_IP}:${pubPort}`; } function inbound(pubKey: string): void { const inside = table.get(pubKey); if (inside) console.log(`IN reply to ${pubKey} delivered inside to ${inside}`); else console.log(`IN reply to ${pubKey} DROPPED (no table entry - unsolicited)`); } // Two inside hosts, both using source port 52001 to the same server: const a = outbound("192.168.1.10", 52001, "93.184.216.34:443"); const b = outbound("192.168.1.23", 52001, "93.184.216.34:443"); outbound("192.168.1.10", 52014, "142.250.72.14:80"); console.log("--- replies come back ---"); inbound(a); // resolves to .10 inbound(b); // resolves to .23, NOT .10 - the ports disambiguate // An UNSOLICITED packet from the outside (nobody asked for it): inbound("203.0.113.5:55555"); // no mapping -> dropped

NAT solved the address crunch brilliantly — but it broke a founding principle of the Internet.

The cost: NAT breaks the end-to-end principle

The original Internet promised that any host could address any other host directly — the end-to-end principle. NAT quietly revokes that promise. An inside device has no publicly reachable address of its own; it exists, from the outside, only as a temporary row in a table that appears when it initiates a connection and evaporates when idle. This has real consequences:

It is tempting to say "NAT protects me — outsiders can't reach my devices." There is a grain of truth: because unsolicited inbound packets have no table entry, they are dropped, which incidentally hides inside hosts. But that safety is a side effect, not a security design, and leaning on it is dangerous:

The one-liner: NAT conserves addresses; a firewall enforces policy. Do not confuse an accident of address translation for a deliberate security boundary.

IPv6: end scarcity, don't manage it

IPv6 takes the opposite tack: instead of squeezing more life out of 32 bits, it moves to 128 bits. The number of addresses becomes 2^{128}2^{128} \approx 3.4 \times 10^{38}, so vast that you could assign an address to every atom on the surface of the Earth and barely dent it. Scarcity, and with it the reason for NAT, simply disappears. Every device can once again have its own globally unique, directly reachable address — the end-to-end principle restored.

128 bits are written as eight groups of four hex digits, separated by colons:

\texttt{2001:0db8:0000:0000:0000:ff00:0042:8329}

That is a mouthful, so IPv6 has two compression rules that shorten it dramatically:

Applying both, the address above collapses to:

\texttt{2001:db8::ff00:42:8329}

The :: stands in for "however many all-zero groups it takes to make eight total". So ::1 is the loopback (seven zero groups then 1), and :: alone is the all-zeros address. Because you may use :: only once, an address like 2001:0:0:1:0:0:0:1 must choose which zero-run to collapse (the longer one), giving 2001:0:0:1::1 — not 2001::1::1, which is illegal and un-parseable.

The long crossover: dual stack and tunnelling

You cannot flip the whole Internet to IPv6 on a Tuesday — hundreds of millions of devices, routers and services would have to change at once. So the transition has been gradual, and two mechanisms carry it:

The upshot is a strange, drawn-out coexistence: IPv6 adoption keeps climbing (past half of Google's traffic in many countries), yet NAT'd IPv4 stubbornly persists. The "temporary" stopgap and its replacement have shared the road for two decades — a reminder that on the Internet, nothing is more permanent than a good temporary fix.

There was an "IPv5" — sort of. The version number 5 in the IP header was assigned to an experimental 1979 protocol called ST (the Internet Stream Protocol), designed for real-time voice and video. It never became a general-purpose successor to IPv4, but it had already claimed version number 5. So when the next-generation IP was designed in the 1990s, it took the next free number: 6. There is no missing IPv5 conspiracy — just a version number quietly spent on a research protocol before the real successor arrived.