RFC 2131 and the Metastability of Ping Checks
Trading deterministic local operations for synchronous network coordination transforms innocent safety checks into catastrophic vulnerabilities.
By Owen Tate
Sparked by An unusual way for your DHCP server to run out of dynamic IPs · discussion

In 1997, the authors of RFC 2131 added a seemingly innocuous safety recommendation for DHCP: "The server SHOULD probe the reused address before allocating it, e.g., with an ICMP echo request." It sounds perfectly reasonable. Why hand out an IP address if a rogue device on the network is already squatting on it? Most modern implementations, including ISC DHCP, followed suit by enabling ping-check true by default. We can think of this as pessimistic concurrency. It is the architectural equivalent of a busy coat-check attendant who, instead of trusting their internal ledger, shouts into the lobby—"Is anyone holding coat #42?!"—and waits a full second before handing out a ticket. It works beautifully in pristine conditions. Until a troll walks in.
I was reading through Chris Siebenmann's excellent write-up of a "screaming host" incident recently, and it perfectly illustrates the structural flaw hiding inside this innocent recommendation. Fundamentally, a DHCP server operates as an $O(1)$ memory lookup table. It allocates leases out of a pre-computed pool. On modern hardware, that local operation should comfortably handle thousands of requests per second. But the moment you introduce that ICMP check, you mathematically transform a local, deterministic memory allocation into a distributed, synchronous coordination problem over an untrusted network.
Let's isolate the variable causing the collapse. According to the dhcpd.conf man page, when the server probes an address, it pauses for exactly 1 second to wait for an ICMP reply. If we look at this through the lens of queuing theory, that single safety check places a hard ceiling on the server's throughput. By blocking the main allocation thread to listen for a response over the network, our service rate ($\mu$) is artificially capped at exactly 1 request per second.
In reality, inputs are rarely perfectly behaved Poisson arrivals. The pristine academic protocol assumes that clients will back off and respect the limits. In Siebenmann's incident, a single misconfigured host on the network ignored the rules and started relentlessly spamming DHCP requests. A seemingly minor hardware fault had found the protocol's hidden bottleneck.
Let's run the math on what happens to our queue depth as load escalates. As long as the arrival rate ($\lambda$) of new DHCP requests remains well below 1 per second, the system survives. The attendant shouts, waits a second, hears nothing, and hands out the coat. We can model this using a standard M/M/1 queue. The laws of probability dictate that as the arrival rate approaches the service rate ($\lambda \to \mu$), the expected queue length grows exponentially.
Let's say the screaming host pushes the arrival rate to $\lambda = 0.9$ requests per second. The server is spending 90% of its time blocked on ICMP timeouts. The math tells us the average queue length is $\frac{\lambda}{\mu - \lambda}$, which equals 9 waiting requests. The system is heavily stressed, but functional.
But what if the host sends 2 requests per second? When $\lambda \ge \mu$, the denominator becomes zero or negative. The queue length mathematically guarantees a trajectory to infinity.[^1] A single misconfigured device sending just two packets a second pushes the entire server into a state of metastable collapse. Total gridlock.
[^1]: Assuming an unbounded queue. In practice, you hit a memory limit or a socket buffer fills up and drops packets on the floor, which simply triggers more retries from the starved clients.
It actually gets worse. As pointed out in the Hacker News discussion regarding the incident, the local network topology often conspires to make this synchronous lock even more punitive. The collapse compounds beyond sheer request volume, structurally exacerbated by Layer 2 proxy_arp misconfigurations.
If a router on the subnet is improperly configured to answer every single ARP broadcast (a state often conflated by operators with a NIC running in promiscuous mode), the server's safety check breaks in the most pathological way possible. The server sends the ICMP echo, and the router immediately replies on behalf of the phantom IP. The ping always succeeds. The DHCP server dutifully spends its 1-second budget validating a ghost, fails the lease allocation because it assumes the IP is legitimately taken, and forces the client to retry. Which triggers another request. Which triggers another ping. Which triggers another proxy reply. A perfectly deterministic trap.[^2]
[^2]: Which solves the IP collision problem by guaranteeing nobody ever gets a lease. A pyrrhic victory.
When that queue depth hits infinity, it escapes the whiteboard asymptote and translates into a blaring on-call alert for an exhausted engineer at 3 AM.
Put yourself in their shoes. On the monitoring dashboard, the DHCP service looks entirely unresponsive. The queue of pending leases is maxed out, valid clients are dropping off the network, and the failure domain is expanding by the minute. Yet, bewilderingly, the CPU utilization on the DHCP server is completely idle. We have a service that appears dead, but refuses to show any signs of resource exhaustion.
The operator—likely lacking deep Layer 2 network visibility from their application metrics—is flying entirely blind. They have been left holding the bag because the architecture betrayed them, masking a localized network anomaly as a catastrophic service outage. By attempting to solve an occasional IP conflict with a synchronous network call, the RFC authors accidentally designed a system that scales linearly with the worst behavior of its most broken participant.
We must treat synchronous network calls with extreme prejudice: safety checks that trade local operations for distributed coordination are simply outages waiting for an inevitable hardware hiccup—leaving a blind, 3 AM operator to catch the falling math.