Every IPv4 packet traversing the Internet carries a 16-bit Identification field (IP ID) within its binary header. Defined in 1981 under RFC 791, this field enabled destination operating systems to reassemble fragmented IP datagrams exceeding intermediate path MTUs. For decades, kernel developers implemented this field as a simple global incrementing integer: every time a machine transmitted an IP packet, its internal counter increased by one.
What seemed like an innocent utility became one of the most elegant side-channel vulnerabilities in networking history. By observing sequential changes in a remote machine's IP ID counter, an attacker can map firewalled ports on distant target servers without sending a single packet from their own IP address, deduce private network relationships, and count packet transmissions across subnets.
Modern standards, particularly RFC 6864 and secure transport protocols like WireGuard, systematically restructured how operating systems manage IP identification. Examining this side channel illustrates core principles of transport security, OS state isolation, and encrypted tunnel defense.
+-------------------------------------------------------------------------+
| THE CLASSIC IDLE SCAN ATTACK TRIANGLE |
+-------------------------------------------------------------------------+
| |
| 1. Probe IP ID (SYN/ACK) 2. Spoofed SYN (Source=Zombie) |
| Zombie IP ID = 31337 Target Port 443 |
| ┌─────────────────────────┐ ┌─────────────────────────┐ |
| │ ▼ │ ▼ |
| [Attacker] [Zombie Host] [Target Server]|
| ▲ │ ▲ │ |
| │ └───────┼─────────────────────────┘ |
| 3. Probe IP ID (SYN/ACK) │ Target replies SYN/ACK |
| Zombie IP ID = 31339 │ Zombie sends RST (IP ID + 1!) |
| Delta = 2 -> PORT IS OPEN! └─────────────────────────┘ |
+-------------------------------------------------------------------------+
The Origins of the IPv4 Identification Field (RFC 791)
Under RFC 791, intermediate routers encountering datagrams larger than the next hop MTU must fragment them. To ensure the destination host correctly reassembles fragments belonging to distinct packets, the sender assigns an identifier to each datagram.
The receiver reconstructs fragments using a 4-tuple:
- Source IP Address
- Destination IP Address
- Protocol Identifier (e.g., TCP, UDP, ICMP)
- Identification Value (
IP ID)
Because 16 bits allow 65,536 values, early operating systems (classic Windows, BSD, and historical Linux kernels) maintained a shared global variable:
// Historical kernel implementation: global monotonic increment
static unsigned short global_ip_id = 0;
void build_ip_header(struct iphdr *iph) {
iph->id = htons(++global_ip_id);
}
This predictable design created an inadvertent telemetry leak: external observers could infer exactly how many packets a host sent over any time window.
Anatomy of the Idle Scan: Blind Port Scanning via Zombie Hosts
In 1998, security researcher Salvatore Sanfilippo (antirez) revealed that predictable IP ID counters enabled stealthy blind port scanning. Named the Idle Scan (implemented in Nmap as -sI), this attack scans a target without transmitting any packets from the attacker's real IP address.
The attack requires three roles:
- The Attacker: Orchestrates probes and spoofed traffic.
- The Zombie Host: An idle machine incrementing its IP ID globally with negligible background traffic.
- The Target Server: The system whose firewall filtering and open ports are evaluated.
Reconnaissance manipulates the target into replying to the zombie, observing side-channel deltas on the zombie's counter.
Step-by-Step Technical Execution of an Idle Scan
An Idle Scan tests each target port through three coordinated steps:
- Baseline Probe: The attacker sends an unsolicited
SYN/ACKpacket to the zombie. Lacking a matching TCP state, the zombie answers with aRSTcontaining its current identifier ($IPID_1 = 1000$). - Spoofed Probe: The attacker sends a raw
SYNpacket to the target port (e.g., 443), forging the IP header source address to match the zombie's IP. - Delta Probe: The attacker sends a second
SYN/ACKto the zombie, eliciting anotherRSTwith updated identifier ($IPID_2$).
State Transition Analysis: Open, Closed, and Filtered Ports
The delta ($\Delta = IPID_2 - IPID_1$) exposes the target port state:
+-------------------------------------------------------------------------+
| PORT STATE DETERMINATION TABLE |
+-------------------------------------------------------------------------+
| Target Port State | Target Reaction to Spoofed SYN | Zombie Delta (Δ) |
| :--- | :--- | :--- |
| OPEN | Sends SYN/ACK to Zombie | Δ = 2 (Port Open) |
| | Zombie replies RST (consumes ID) |
| CLOSED | Sends RST to Zombie | Δ = 1 (Port Closed)|
| | Zombie drops RST (no packet) | |
| FILTERED (Drop) | Discards packet silently | Δ = 1 (No response)|
| | Zombie receives nothing | |
+-------------------------------------------------------------------------+
- Open Port ($\Delta = 2$): The target accepts the connection and returns
SYN/ACKto the zombie. The zombie, receiving an unpromptedSYN/ACK, sendsRSTto the target, incrementing its IP ID. When the attacker probes in Step 3, the counter has advanced by two. - Closed or Filtered Port ($\Delta = 1$): If closed, the target sends
RSTto the zombie (which drops it). If filtered, the target drops the packet. In both scenarios, the zombie transmits nothing, advancing by only one unit from the attacker's second probe.
Firewall and IDS logs record only the zombie's address, concealing the attacker.
Traffic Volume Inference and Cross-Network Host Tracking
Beyond port scanning, predictable IP ID sequences enable remote traffic analysis:
- Traffic Rate Monitoring: Polling an IP ID at fixed intervals calculates outbound packet frequency, exposing scheduled backups or administrative sessions.
- Detecting Internal Peer Links: Correlated increment steps between internal servers reveal active communication channels without packet payloads.
- Cross-Network Device Tracking: Historical laptops roaming Wi-Fi networks exposed static IP ID seeds, allowing tracking across subnets.
RFC 6864 Standardization: Eliminating IP ID on Atomic Datagrams
The IETF standardized defenses in RFC 6864: Updated Specification of the IPv4 ID Field (2013).
Because Path MTU Discovery (PMTUD, RFC 1191) sets the Don't Fragment (DF = 1) bit on almost all TCP/UDP traffic, packets with DF = 1 not currently fragmented are atomic datagrams.
RFC 6864 established clear requirements:
- Zeroing Identifiers: Senders may set the IP ID of atomic datagrams to
0x0000. - Receiver Exemption: Receiving operating systems MUST NOT require unique IP IDs when
DF = 1. - Deprecating Global Counters: Kernels MUST NOT maintain shared counters across unrelated destinations.
+-------------------------------------------------------------------------+
| RFC 6864 ATOMIC DATAGRAM IDENTIFICATION |
+-------------------------------------------------------------------------+
| IPv4 Header: |
| [ Version: 4 ] [ IHL: 5 ] [ DSCP/ECN ] [ Total Length: 1500 ] |
| [ Identification: 0x0000 ] <--- RFC 6864: Set to 0 for Atomic Packets |
| [ Flags: DF=1, MF=0 ] [ Fragment Offset: 0 ] |
| [ TTL: 64 ] [ Protocol: 6 (TCP) ] [ Header Checksum ] |
| [ Source IP ] [ Destination IP ] |
+-------------------------------------------------------------------------+
Modern Operating System Defenses: Linux and BSD Implementations
Modern kernels isolate IP ID generation from global state machines.
Per-Socket Hash Tables and Cryptographic PRNG Generation
Operating systems implement isolated randomization:
- Linux Kernel Architecture: Modern Linux kernels set
iph->id = 0on atomic datagrams. For non-atomic datagrams, Linux hashes destination, source, protocol, and a secret salt (siphash) into a hash table, isolating counters per peer. - BSD & macOS PRNGs: OpenBSD and FreeBSD use cryptographic pseudo-random number generators (PRNG) to generate unpredictable sequences per association.
- Windows Implementation: Windows 10, 11, and modern Windows Server versions employ per-peer randomized sequences.
How Layer-3 VPN Tunnels and RiceGuard Neutralize IP ID Leaks
Layer-3 VPN tunnels operating in TUN mode (WireGuard and OpenVPN) provide architectural immunity against IP ID side channels.
VPNRice engineers its infrastructure with rigorous encapsulation and transport hygiene. Leveraging the RiceGuard protocol, client traffic is encrypted in authenticated UDP packets before traversing external networks.
+-------------------------------------------------------------------------+
| RICEGUARD ENCAPSULATION AND IP ID ISOLATION |
+-------------------------------------------------------------------------+
| Internal Client OS Stack: |
| [ Inner IP Packet: TCP SYN to Target | Inner IP ID: OS Generated ] |
| │ |
| ▼ |
| RiceGuard Tunnel Engine: |
| [ ChaCha20-Poly1305 Encrypted Payload (Inner Header Obfuscated) ] |
| │ |
| ▼ |
| External Wire Transit: |
| [ Outer IPv4 Header: UDP 51820 | Outer IP ID = 0x0000 (RFC 6864) ] |
+-------------------------------------------------------------------------+
RiceGuard neutralizes side-channel observation through three safeguards:
- Header Encapsulation: The internal IPv4 header and its IP ID are encrypted inside ChaCha20-Poly1305 payloads. External observers cannot correlate inner identifiers.
- RFC 6864 Outer Zeroing: Outgoing UDP packets enforce
DF = 1with outerIP ID = 0x0000, offering zero measurable deltas. - Cryptographic Anti-Spoofing: Endpoints verify public keys prior to processing; spoofed probes targeting the endpoint are dropped without altering transport counters.
Users seeking side-channel resistant network protection can obtain the client on the VPN download page.
Practical Testing: Detecting Vulnerable Zombie Hosts with Nmap
Auditors test candidate hosts for predictable counter increments using Nmap:
# Test whether a host exhibits incremental IP ID generation
nmap -p 80,443 --script ipidseq 198.51.100.25
# Vulnerable output:
# |_ipidseq: Incremental! (Vulnerable to Idle Scan)
# RFC 6864 compliant output:
# |_ipidseq: All zeros! (Secure: RFC 6864 compliant)
If a host is incremental, an auditor can verify scanning against authorized targets:
# Execute Idle Scan using candidate zombie host
nmap -Pn -sI 198.51.100.25:80 203.0.113.50
When targets enforce randomized or zeroed IDs, Nmap halts with Cannot use zombie host: IP ID sequence is not incremental.
Architectural Comparison: Global vs Randomized IP ID Generation
| Security Property | Global Monotonic Counter | Per-Peer Hashed Counter | RFC 6864 Zeroed (RiceGuard) |
|---|---|---|---|
| Idle Scan Exploitability | Vulnerable | Immune (Isolated peers) | Immune (Zero identifier) |
| Traffic Rate Estimation | Possible externally | Prevented for third parties | Prevented for third parties |
| Device Tracking Potential | High (Sequential leak) | Negligible | Zero (Stateless zero field) |
| Fragmentation Support | Full support | Full support (Peer hash) | Full support via PMTUD |
| Kernel Memory Overhead | 2 bytes (Global variable) | Moderate (Hash entries) | Zero (Constant value) |
| CPU Processing Cost | Minimum (++counter) |
Low (SipHash calculation) | Minimum (Fixed 0x0000) |
The Transition to IPv6: Eliminating the Base Header Identifier
The permanent architectural fix for IP ID leaks arrived with IPv6 (RFC 8200).
Because fragmentation occurs in under 0.1% of modern traffic, IPv6 removed the Identification field from its 40-byte base header. Intermediate routers never fragment IPv6 datagrams; fragmentation occurs solely at the source using an optional Fragment Extension Header:
+-------------------------------------------------------------------------+
| IPV6 HEADER PURITY: ZERO STATIC ID |
+-------------------------------------------------------------------------+
| IPv6 Base Header (40 Bytes Fixed): |
| [ Version: 6 ] [ Traffic Class ] [ Flow Label: 20 bits ] |
| [ Payload Length: 16 bits ] [ Next Header: 6 (TCP) ] [ Hop Limit: 64 ] |
| [ Source IPv6 Address: 128 bits ] |
| [ Destination IPv6 Address: 128 bits ] |
| |
| * NO IDENTIFICATION FIELD EXISTS IN THE BASE HEADER! * |
+-------------------------------------------------------------------------+
With no identifier in atomic datagrams, idle scanning is structurally impossible under IPv6.
System Administrator Checklist for IP ID Side-Channel Defense
Administrators should enforce the following controls across their infrastructure:
- Enforce RFC 6864 Standards: Deploy Linux kernels 4.0+ to ensure atomic datagrams carry an IP ID of zero.
- Support PMTUD: Permit ICMP Type 3 Code 4 (Fragmentation Needed) through firewalls to prevent fragmentation black holes.
- Deploy Anti-Spoofing (BCP 38): Enable Unicast Reverse Path Forwarding (
uRPF) on border routers to reject spoofed internal IPs. - Encrypt Inter-Site Traffic: Route inter-server management traffic via RiceGuard tunnels to conceal transport metadata.
- Retire Obsolete Kernels: Decommission legacy operating systems that still maintain global sequential counters.
Modern network architectures have successfully neutralized the IP ID side channel, preventing packet header fields from compromising host security.



