Why Receiving a TCP RST Doesn’t Always Close the Connection
This article explains the purpose of the TCP RST flag, how the kernel and application layers detect it, the various scenarios that trigger RST, why an RST may not terminate a connection, and the security implications of RST attacks.
What is RST
In normal TCP communication a connection is closed gracefully with a four‑way handshake, but in abnormal situations the RST flag is used to forcefully terminate a connection. When a packet with the RST flag is received, the kernel releases the associated resources and the connection is considered closed.
The receiving side typically sees a connection reset or connection refused error.
How to Know an RST Was Received
The kernel and the application layer are separate; the application can only interact with the kernel via send / recv. When the kernel receives an RST, it marks the socket as closed. Subsequent reads produce Connection reset by peer, and writes produce Broken pipe.
Scenarios That Produce RST
RST is typically sent when the remote port is unavailable or when a socket is closed prematurely.
Port Unavailable
If a port has never been listened on, or if a previously listening service crashes, the kernel cannot find a matching socket in its global hash table and sends an RST.
// net/ipv4/tcp_ipv4.c (simplified)
int tcp_v4_rcv(struct sk_buff *skb) {
// lookup socket
sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
if (!sk)
goto no_tcp_socket;
if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
// error handling
} else {
// send RST
tcp_v4_send_reset(NULL, skb);
}
}If the checksum is valid, the kernel sends an RST; otherwise the packet is dropped.
Checksum verifies that a packet has not been altered during transmission. If the checksum fails, the packet is discarded without sending an RST.
Socket Closed Prematurely
When the local socket’s receive buffer still holds unread data and the application calls close(), the kernel discards the buffered data and sends an RST to the peer.
If the remote side has already closed its socket, any further data sent by the local side will cause the remote kernel to reply with an RST.
Does Receiving an RST Always Disconnect?
No. The kernel first validates the sequence number against the receive window. If the sequence is outside the window, the RST is silently discarded.
// net/ipv4/tcp_input.c (simplified)
static bool tcp_validate_incoming(void) {
struct tcp_sock *tp = tcp_sk(sk);
if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
goto discard;
}
if (th->rst) {
if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt)
tcp_reset(sk);
else
tcp_send_challenge_ack(sk);
goto discard;
}
}The receive window is the yellow region in the diagram; only RSTs with a sequence inside this window are processed.
Why Validate the Window?
Without validation, an attacker could forge an RST with spoofed IP/port information and force a connection reset, known as an RST attack.
Challenge ACK and Seq Guessing
When an out‑of‑window SYN is received, the kernel replies with a challenge ACK containing a valid sequence number. Attackers can use this value to narrow the range for blind in‑window RST attacks.
Summary
RST is a TCP flag used to abort connections in abnormal situations.
The kernel handles RST; the application perceives it via Connection reset by peer or Broken pipe errors.
RST packets do not require ACK, so lost RSTs are harmless; retransmission or keepalive will trigger a new RST if needed.
Receiving an RST does not always close the connection; the packet’s sequence must fall within the receive window.
Valid‑window RSTs can be abused for attacks, but window validation raises the attack cost.
NiuNiu MaTe
Joined Tencent (nicknamed "Goose Factory") through campus recruitment at a second‑tier university. Career path: Tencent → foreign firm → ByteDance → Tencent. Started as an interviewer at the foreign firm and hopes to help others.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
