Under RFC 1122 and RFC 9293, which ICMPv4 Destination Unreachable codes should make TCP abort a connection, and why do most stacks not abort established ones?
answer
- routing transients versus dead ends
- codes 0, 1, 5 against 2 to 4
- MUST NOT versus SHOULD
- forged errors and blind resets
- is the quoted sequence in flight?
basics
~20 sTCP MUST NOT abort on Destination Unreachable codes 0, 1 or 5 (soft errors) and SHOULD abort on codes 2 to 4 (hard). Most stacks soften hard errors once synchronized, since forged ICMP could otherwise reset connections (RFC 5927).
solid answer
~50 sRFC 1122 §4.2.3.9, restated in RFC 9293 §3.9.2.2, splits ICMP errors for TCP in two. **Soft errors** — Destination Unreachable codes `0` (net), `1` (host) and `5` (source route failed), plus Time Exceeded and Parameter Problem — may be routing transients, so TCP MUST NOT abort; it keeps retransmitting and SHOULD tell the application. **Hard errors** — codes `2` to `4` (protocol, port, fragmentation needed) — SHOULD abort. RFC 5927 explains why most stacks ignore that SHOULD in synchronized states: an ICMP error is unauthenticated, so anyone who can guess a connection's addresses and ports could forge a hard error and reset it blindly; codes 2 and 3 should not appear mid-connection anyway; and code 4 is soft for a TCP doing Path MTU Discovery. Many stacks also check that the quoted sequence number is in flight.
go deeper
Recall that TCP sorts ICMP errors into soft ones it rides out and hard ones that may end a connection, and that net and host unreachable are soft.
Explain which Destination Unreachable codes RFC 1122 and RFC 9293 call soft and hard, and what TCP does with each while it keeps retransmitting.
Explain why stacks soften hard errors in synchronized states, the blind-reset attack behind that, the sequence-number check, and why connection attempts still fail fast.
Weigh fast reaction to genuine path failures against resistance to forged errors, and argue where in a system that choice should be made and by whom.
## Why TCP listens to ICMP at all TCP learns about the path mostly from its own acknowledgements and timers, but ICMP errors carry information TCP cannot get otherwise. RFC 9293 says a TCP implementation MUST act on an ICMP error passed up from IP, directing it to the connection that caused it; the demultiplexing information is the IP header and first transport bytes quoted inside the ICMP message (addresses and ports). The question is how strongly to react. ## Soft errors and hard errors RFC 1122 §4.2.3.9 set the rule, and RFC 9293 §3.9.2.2 restates it: | Class | ICMPv4 messages | Required reaction | Why | |---|---|---|---| | **Soft** | Destination Unreachable codes 0, 1, 5; Time Exceeded codes 0, 1; Parameter Problem | MUST NOT abort; SHOULD make the information available to the application | routing can heal; the next retransmission may get through | | **Hard** | Destination Unreachable codes 2, 3, 4 | SHOULD abort | protocol missing, port closed, or a packet that cannot pass as sent | A soft error does not end anything: TCP notes it and keeps retransmitting until its normal retransmission limits are reached, at which point the noted error can explain the timeout. The two lists are the RFCs' examples; codes added later, such as RFC 1812's code 13, appear in neither, so how a stack treats them is an implementation choice. ## Why most stacks soften the hard errors RFC 5927 (Informational, "ICMP Attacks against TCP") documents that most popular TCP implementations treat **all** ICMP hard errors received in any **synchronized state** (ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT) as soft errors. Its reasoning: - **ICMP errors are not authenticated.** To be matched to a connection, a forged error needs only a plausible quoted header. An attacker who can guess the four-tuple can send a "hard error" and abort the connection without ever seeing its traffic: a **blind connection-reset attack**. Protecting TCP segments themselves does not stop it, because the attack never touches a TCP segment. - **Codes 2 and 3 are implausible mid-connection.** Protocol or port unreachable would mean the peer's transport vanished while the connection was open; RFC 5927 calls that unusual. - **Code 4 is soft for Path MTU Discovery.** For a TCP doing PMTUD, fragmentation needed means "send smaller", not "give up". - **ICMP is unreliable anyway.** A transport should not depend on it: a connection that is really dead will time out, and the application can still be told. The cost, which RFC 5927 states openly, is responsiveness: treating hard errors as soft may stop TCP from reacting quickly to a legitimate one. ## Checking that an error is plausible RFC 5927 §4.1 describes a validation many TCP implementations apply: act only on an ICMP error whose quoted TCP sequence number lies within the data sent but not yet acknowledged, `SND.UNA =< SEG.SEQ < SND.NXT`. An error quoting anything else is discarded. Even an attacker who knows the four-tuple must then also hit the window of in-flight data, and for an endpoint with nothing in flight the check rejects every forged error. ## Connection establishment is the exception During an open attempt the trade-off flips. RFC 9293 notes that it is widespread implementation behaviour to treat soft errors as hard **during connection establishment**. That is why an attempt to reach an unrouted network commonly fails at once with a net unreachable, instead of retransmitting SYNs for the at least three minutes RFC 9293 otherwise requires before the open attempt times out. RFC 9293 also lists an ICMP Port Unreachable, alongside a RST, as a way an open attempt can fail. ## Putting it together For an ICMPv4 Destination Unreachable arriving at a TCP endpoint, a typical modern stack reasons in this order: 1. **Match it**: find the connection from the quoted addresses and ports; no match, no action. 2. **Validate it**: if the stack applies RFC 5927's check, discard it unless the quoted sequence number is in flight. 3. **Check the state**: during an open attempt, many stacks fail the attempt at once; in a synchronized state, many treat it as soft. 4. **Handle code 4 separately**: feed the reported next-hop MTU to Path MTU Discovery and send smaller segments. 5. **Remember it**: keep the error so that, if the connection later times out, the application can be told why. ## The UDP contrast UDP has no connection to abort. RFC 1122 says UDP MUST pass every ICMP error it receives to the application layer, and the application decides what a net or port unreachable means for it. RFC 9293 also says TCP MUST silently discard ICMP Source Quench, which RFC 6633 deprecated.
- Why does TCP commonly fail fast on a net unreachable while connecting but ignore one on an established connection?During establishment there is no investment to protect and a quick answer helps the application, so RFC 9293 notes it is widespread practice to treat soft errors as hard then. On an established connection the error may be a routing transient or a forgery, so code 0 stays soft: TCP keeps retransmitting and only its own timers end the connection.
- What does the sequence-number check described in RFC 5927 protect against, and what can it not stop?It discards ICMP errors whose quoted TCP sequence number is outside the unacknowledged data, `SND.UNA` to `SND.NXT`, so a blind forger must guess the four-tuple and an in-flight sequence number. It cannot stop an attacker who sees the traffic and can copy a valid quoted header, and with nothing in flight it discards legitimate errors too, so the connection learns of a real failure only through its own timers.
saying these in an interview costs you the question
- Any ICMP unreachable received by TCP immediately closes the connection.
- A host unreachable on an established connection must abort it.
- TCP ignores ICMP entirely because it has its own retransmissions.
- Encrypting TCP payloads protects a connection from forged ICMP resets.
- Soft and hard errors apply only to UDP sockets.