2026-07-23
If you have ever run an IPsec VPN from a coffee shop, a hotel, or basically anywhere behind a home router, you owe your working tunnel to RFC 3947. It solves one of the most philosophically awkward collisions in the history of the internet: IPsec was designed to protect the integrity of IP headers, and NAT exists specifically to rewrite them.
The core problem. IPsec's Authentication Header (AH) computes an integrity check over the IP source and destination addresses. NAT changes those addresses. Result: every packet is discarded as tampered. ESP without AH survives header rewrites, but ESP has no port numbers. A NAT box tracking outbound flows uses the 5-tuple to demux return traffic — with ESP, all it sees is protocol number 50 and two IP addresses. Two clients behind the same NAT establishing ESP tunnels to the same responder are indistinguishable on the return path. IKE itself runs over UDP/500, and many early NATs rewrote the source port, breaking the cookie exchange that assumes port 500 on both sides.
The detection trick. RFC 3947 adds two new IKE payloads exchanged in Phase 1: NAT-D (NAT-Discovery) payloads containing HASH(CKY-I | CKY-R | IP | Port). Each peer computes the hash of what it thinks its own IP and port are, and what it thinks the peer's IP and port are, then sends both. The receiver recomputes locally. If the hash of the received "your IP" matches what the receiver actually sees, there is no NAT in front of the sender. If it doesn't match, a NAT was between them. This elegantly distinguishes "NAT in front of me" from "NAT in front of the peer," which matters for keepalive scheduling.
The vendor-ID dance. Because RFC 3947 was the successor to years of vendor-specific NAT-T drafts (each with its own incompatible IKE vendor ID hash), a compliant implementation typically sends multiple vendor ID payloads — the RFC 3947 hash 4a131c81070358455c5728f20e95452f plus draft-02, draft-03, and Microsoft variants — and picks the highest common denominator. Wireshark captures of any IKE exchange still show this fossil record.
The float to 4500. Once NAT is detected, both peers switch subsequent IKE traffic (and all ESP traffic) to UDP port 4500. This is the "IKE port floating" that RFC 3948 defines. ESP packets get a four-byte UDP header prepended, giving NAT the port numbers it needs to demux flows. A four-byte "non-ESP marker" of all zeros distinguishes IKE messages from ESP-in-UDP on the same 4500 socket — since a real ESP SPI is never zero, the demultiplexer can tell them apart.
Why it still matters. Every strongSwan, Libreswan, Windows built-in VPN, iOS/macOS IKEv2 client, and enterprise firewall implements this. IKEv2 (RFC 7296) folded NAT-T into the base spec, but the mechanism is identical — hash-based detection, port float to 4500, ESP-in-UDP encapsulation. Modern WireGuard sidesteps the whole mess by being UDP-native from day one, which is arguably a delayed acknowledgment that RFC 3947 was papering over a design mismatch that shouldn't have existed. But until WireGuard is universal, 4500/udp remains one of the most important port numbers most engineers have never had to think about.
Historical footnote. The RFC was published January 2005, but drafts circulated from 2001. Cisco, Microsoft, and SafeNet all shipped incompatible pre-standard versions, which is why the vendor-ID negotiation is so byzantine — the RFC had to codify backward compatibility with its own prehistory.
