SYN Floods and TCP-Layer Attacks
Half-open connections, SYN cookies, retransmission timeouts — the security and resilience knobs on TCP.
Summary#
A SYN flood exploits the cheapest asymmetry in TCP: the server commits real state on receiving a SYN (allocates a Transmission Control Block, starts a retransmit timer for the SYN-ACK), but the client commits nothing — and the source IP in the SYN is trivially spoofable. An attacker sends a stream of SYNs from random source IPs, fills the listen queue with half-open connections, and starves legitimate clients. The defence — SYN cookies, plus connection-table limits, plus retransmission tuning — is one of the oldest deployed counters to a DoS attack and is still the right answer.
Beyond SYN floods, the same kind of resource asymmetry shows up in other TCP-layer attacks: RST injection, sequence-number guessing, slow-read (Slowloris), and amplification via misconfigured services. The TCP retransmission timer is at the centre of several of them — it’s also the place defences hook in. This writeup covers SYN floods in depth and the broader family of TCP-layer attacks around them.
Why it matters#
Every service that listens on a public port faces this attack. Network appliances and cloud load balancers handle it for you when you’re behind them; bare-metal servers need to know the kernel knobs. SRE interviews ask “what is a SYN flood and how do you defend against it” routinely — the wrong answer (“more bandwidth”) signals shallow protocol knowledge.
It also matters because the SYN cookie technique is a beautiful piece of protocol engineering — stateless validation using only the SYN-ACK sequence number as a cryptographic carrier. Understanding it sharpens your sense of what’s possible when you accept that “the client will echo back our chosen value.”
How it works#
The vulnerability#
Recall the three-way handshake:
client server | -- SYN, seq=X ----------------> | (server allocates TCB, queues half-open) | <- SYN-ACK, seq=Y, ack=X+1 ---- | (server starts retransmit timer) | -- ACK, seq=X+1, ack=Y+1 -----> | (handshake complete; moves to ESTABLISHED)On step 1 the server has committed memory (a Transmission Control Block) and a timer (to retransmit the SYN-ACK if the third ACK never comes). The client has sent one packet from a forgeable source IP. If the third ACK never arrives, the server eventually times out the half-open slot — but the default RTO retries take 30+ seconds.
An attacker spraying SYNs at 100k/s from random source IPs fills the half-open queue immediately. Legitimate clients’ SYNs are dropped (tcp_max_syn_backlog exceeded), or the queue accepts but never makes progress.
SYN cookies#
Bernstein’s 1996 trick: instead of allocating a TCB on the SYN, encode the connection’s identifying state into the SYN-ACK’s initial sequence number Y itself. If the client is real, it echoes Y+1 in the third ACK; the server validates that the echoed value is a properly-signed cookie and only then allocates the TCB.
The cookie structure (simplified):
Y = MAC(secret, client_IP, client_port, server_IP, server_port, t) || t || mss_indexwhere t is a coarse timestamp (so old cookies expire) and mss_index encodes the MSS into 3 bits (since the server doesn’t have the original SYN’s options anymore). On the third ACK, the server recomputes the MAC, checks it, decodes the MSS, and synthesises a TCB.
Result: no state until the handshake is complete. Spoofed SYNs cost the server CPU but no memory. Legitimate clients see a normal handshake. Linux enables tcp_syncookies = 1 by default and triggers them when the SYN queue is near full.
Trade-offs of SYN cookies#
- Lose negotiated options. Window scale, SACK permitted, and timestamps are negotiated at SYN/SYN-ACK; SYN cookies discard them. Recent Linux smuggles a few back via the timestamp field, but it’s imperfect.
- No early data. TCP Fast Open’s SYN-borne payload requires per-client cookies; SYN cookies (which are per-connection) clash with it.
- CPU cost on cookie validation. Each ACK requires a MAC computation. Cheap, but non-zero.
Net: keep them as a fallback, enabled only when the SYN queue is saturated. Don’t make them the steady state.
Retransmission timer in the loop#
The server retransmits the SYN-ACK if the third ACK doesn’t arrive. Linux defaults to 5 retries, exponentially backing off — about 63 seconds total. A spoofed SYN holds a queue slot for that entire window. net.ipv4.tcp_synack_retries = 2 cuts the per-spoof cost dramatically. Combined with SYN cookies, this neutralises most floods.
Other TCP-layer attacks#
- RST injection. An off-path attacker who can guess the 5-tuple and approximate sequence number sends a forged RST. Defences: randomise initial sequence numbers (RFC 6528), require the RST’s sequence to fall in the current receive window, RFC 5961’s relaxed acceptance with explicit ACKs.
- Sequence-number guessing. Predictable ISNs let attackers inject data into a connection without seeing it. Mitigation: cryptographically strong ISN generation per RFC 6528.
- Slowloris / slow-read. Application-layer cousin of SYN flood. Client opens a real TCP connection and dribbles bytes one at a time, holding a worker thread. Defences: time-out idle reads, cap concurrent connections per source IP, use event-driven servers (nginx, Envoy) where slow clients cost a socket but not a thread.
- Reflection / amplification. Attacker sends a TCP SYN with the victim’s source IP spoofed; the server replies with SYN-ACK to the victim. Modest amplification (1:1 by packet, but with retransmits). UDP-based reflection (DNS, NTP, memcached) is far more dangerous; TCP’s three-way handshake provides natural rate-limiting.
- TCP-MD5 / TCP-AO bypass. BGP sessions use TCP-MD5 to authenticate peers; attackers who break the MD5 key can inject route updates. TCP-AO (RFC 5925) replaced it with stronger algorithms.
Variants and trade-offs#
synack_retries is tuned down. Other defence trade-offs:
tcp_max_syn_backlog. Larger queue absorbs bursts but uses more memory. Default 128–1024; tune to ~8192 for public-facing servers.tcp_synack_retries. Lower (1–2) abandons spoofed SYNs faster — at the cost of legitimate clients on lossy links seeing more handshake failures.tcp_abort_on_overflow. When the accept queue (not SYN queue) overflows, send RST instead of silently dropping. Faster failure visibility; client retries land sooner.- Connection-rate limits per source IP. Effective when sources are real; useless against IP-spoofed floods.
- Cloud / CDN scrubbing. Anti-DDoS services absorb floods at edge points-of-presence with anycast and SYN-proxying. The economical answer for most internet-facing services.
Why is the SYN-ACK retransmission timer the key knob?
The attacker’s per-SYN cost is fixed (one packet). The server’s cost is the half-open slot held for the SYN-ACK retransmission window. If the server holds a slot for 63 seconds per SYN, a 100k SYN/s attacker pins 6.3 million slots before any timer fires. Cutting retransmit retries from 5 to 2 reduces per-SYN slot holding from 63 s to about 7 s — an order of magnitude less queue pressure for the same defensive cost.
When this is asked in interviews#
Standard SRE / security / networking-deep-dive question. Expect “explain a SYN flood and how you’d defend a service against it.” Strong answers cover: the asymmetry of state (server commits, client doesn’t, source IP spoofable), SYN cookies as the canonical defence (and what they cost), the kernel knobs (syncookies, max_syn_backlog, synack_retries), and the edge-layer mitigation (CDN / scrubbing service).
Common follow-ups:
- “What does a SYN cookie actually encode?” — A MAC over the 5-tuple plus a timestamp, packed into the SYN-ACK’s initial sequence number. The third ACK echoes it; the server re-verifies and reconstructs the TCB.
- “What’s the cost of always-on SYN cookies?” — Loss of negotiated options (window scale, SACK, timestamps) for cookied connections. Modern Linux smuggles some back through timestamps but imperfectly.
- “How is Slowloris different from a SYN flood?” — Slowloris uses real connections and dribbles application-layer data; it attacks application worker pools, not the TCP handshake. Defences are at L7 (idle timeouts, event-driven servers), not L4.
- “Why is UDP amplification worse than TCP reflection?” — UDP has no handshake to validate the source IP, so spoofed requests reach the reflector and the response goes to the victim. TCP’s three-way handshake forces the client to echo the server’s sequence number, preventing one-way reflection at scale.
- “What’s the difference between the SYN queue and the accept queue?” — SYN queue holds half-open connections (after SYN, before ACK). Accept queue holds fully-handshaked connections waiting for the application’s
accept(). Both can overflow; both have separate knobs (tcp_max_syn_backlog,somaxconn).
Asked across security, SRE, and infrastructure loops. Tier-one anti-DoS interview question.
Related concepts#