I discussed some with my friends at the weekend TCP The problem of , In the 《Linux Server high performance programming 》 This book , I found such a sentence written in the book :

The book says , be in TIME_WAIT State connection , After receiving the same Quad SYN after , I'll come back RST message , The other party will disconnect when they receive it .
The author only mentioned such a sentence in the book , There is no evidence of the source code or the snapshot .
At first , I see and think this logic is quite reasonable , But when I ate it myself TCP After the source , It turns out that's not the case .
therefore , Let's talk about this today ,「 stay TCP During normal waving , be in TIME_WAIT State connection , Received the same quadruple SYN What happens after ?」
The phenomenon of the problem is as follows , On the left is the server , On the right is the client :

Say first conclusion
I'm analyzing with you TCP Before the source code , Let me draw a conclusion directly .
In response to this question , The key is to see SYN Of 「 Serial number and timestamp 」 Is it legal , Because in TIME_WAIT Connection status received SYN after , Will judge SYN Of 「 Serial number and timestamp 」 Is it legal , Then do different processing according to different judgment results .
Let me explain to you first , What is? 「 legal 」 Of SYN?
- legal SYN: Client's SYN Of 「 Serial number 」 Than the server 「 Expect the next received serial number 」 want Big , also SYN Of 「 Time stamp 」 Than the server 「 Timestamp of the last message received 」 want Big .
- illegal SYN: Client's SYN Of 「 Serial number 」 Than the server 「 Expect the next received serial number 」 want Small , perhaps SYN Of 「 Time stamp 」 Than the server 「 Timestamp of the last message received 」 want Small .
above SYN Legal judgment is based on the fact that both sides have opened TCP The scenario of timestamp mechanism , If neither side opens TCP Timestamp mechanism , be SYN The legal judgment is as follows :
- legal SYN: Client's SYN Of 「 Serial number 」 Than the server 「 Expect the next received serial number 」 want Big .
- illegal SYN: Client's SYN Of 「 Serial number 」 Than the server 「 Expect the next received serial number 」 want Small .
Received legal SYN
If in the TIME_WAIT Connection status received 「 legal SYN 」 after , This quad connection will be reused , skip 2MSL And turn into SYN_RECV state , Then you can establish the connection process .
Take the following figure as an example , Both sides have enabled TCP Timestamp mechanism ,TSval Is the timestamp when sending the message :

Above picture , After receiving the third wave FIN When the message , The message will be recorded TSval (21), use ts_recent Variable to hold the . Then the accountant calculates the next expected serial number , The next expected serial number of this example is 301, use rcv_nxt Variable to hold the .
be in TIME_WAIT Connection status received SYN after , because SYN Of seq(400) Greater than rcv_nxt(301), also SYN Of TSval(30) Greater than ts_recent(21), So it's a 「 legal SYN」, Then the quad connection will be reused , skip 2MSL And turn into SYN_RECV state , Then you can establish the connection process .
Received an illegal SYN
If in the TIME_WAIT Connection status received 「 Illegal SYN 」 after , will Reply to the fourth wave ACK message , When the client receives , I found that I didn't expect to receive the confirmation number (ack num), Just go back RST The message is sent to the server .
Take the following figure as an example , Both sides have enabled TCP Timestamp mechanism ,TSval Is the timestamp when sending the message :

Above picture , After receiving the third wave FIN When the message , The message will be recorded TSval (21), use ts_recent Variable to hold the . Then the accountant calculates the next expected serial number , The next expected serial number of this example is 301, use rcv_nxt Variable to hold the .
be in TIME_WAIT Connection status received SYN after , because SYN Of seq(200) Less than rcv_nxt(301), So it's a 「 Illegal SYN」, Will reply to the same as the fourth wave ACK message , When the client receives , I found that I didn't expect to receive the confirmation number , Just go back RST The message is sent to the server .
The client has been waiting for some time and still hasn't received SYN + ACK after , Will time out and retransmit SYN message , After the number of retransmissions reaches the maximum , Will disconnect .
PS: Let's bury a question here , be in TIME_WAIT State connection , received RST Will you disconnect ?
Source code analysis
The following source code analysis is based on Linux 4.2 Version of kernel code .
Linux The kernel is receiving TCP After the message , Will execute tcp_v4_rcv function , In this function and TIME_WAIT The main codes related to status are as follows :
int tcp_v4_rcv(struct sk_buff *skb)
{
struct sock *sk;
...
// After receiving the message , This function will be called , Find the corresponding sock
sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), th->source,
th->dest, sdif, &refcounted);
if (!sk)
goto no_tcp_socket;
process:
// If the status of the connection is time_wait, Will jump to do_time_wait
if (sk->sk_state == TCP_TIME_WAIT)
goto do_time_wait;
...
do_time_wait:
...
// from tcp_timewait_state_process Function processing in time_wait Status received message
switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
// If it is TCP_TW_SYN, Then allow this SYN Rebuild the connection
// By allowing TIM_WAIT State transition to SYN_RECV
case TCP_TW_SYN: {
struct sock *sk2 = inet_lookup_listener(....);
if (sk2) {
....
goto process;
}
}
// If it is TCP_TW_ACK, that , Return to memory ACK
case TCP_TW_ACK:
tcp_v4_timewait_ack(sk, skb);
break;
// If it is TCP_TW_RST Direct transmission RESET package
case TCP_TW_RST:
tcp_v4_send_reset(sk, skb);
inet_twsk_deschedule_put(inet_twsk(sk));
goto discard_it;
// If it is TCP_TW_SUCCESS The packet is discarded directly , No response
case TCP_TW_SUCCESS:;
}
goto discard_it;
}
The process of this code :
- After receiving the message , Would call
__inet_lookup_skb()Function to find the corresponding sock structure ; - If the status of the connection is
TIME_WAIT, Will jump to do_time_wait Handle ; - from
tcp_timewait_state_process()Function to process the received message , After processing, do the corresponding processing according to the return value .
Let's talk to you first , If you receive SYN It's legal. ,tcp_timewait_state_process() The function will return TCP_TW_SYN, Then reuse this connection . If you receive SYN It's illegal. ,tcp_timewait_state_process() The function will return TCP_TW_ACK, And then I'll send back what I sent last time ACK.
Next , see tcp_timewait_state_process() How is the function judged SYN Bag .
enum tcp_tw_status
tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
const struct tcphdr *th)
{
...
//paws_reject by false, Indicates that no timestamp wrap has occurred
//paws_reject by true, Indicates that a timestamp wrap has occurred
bool paws_reject = false;
tmp_opt.saw_tstamp = 0;
//TCP There are options in the header and the old connection has the timestamp option enabled
if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) {
// Parsing options
tcp_parse_options(twsk_net(tw), skb, &tmp_opt, 0, NULL);
if (tmp_opt.saw_tstamp) {
...
// Check whether the timestamp of the received message has time stamp loopback
paws_reject = tcp_paws_reject(&tmp_opt, th->rst);
}
}
....
// yes SYN package 、 No, RST、 No, ACK、 The timestamp does not wrap around , And the serial number is not wrapped around ,
if (th->syn && !th->rst && !th->ack && !paws_reject &&
(after(TCP_SKB_CB(skb)->seq, tcptw->tw_rcv_nxt) ||
(tmp_opt.saw_tstamp && // The new connection has a timestamp enabled
(s32)(tcptw->tw_ts_recent - tmp_opt.rcv_tsval) < 0))) { // The timestamp does not wrap around
// Initialization serial number
u32 isn = tcptw->tw_snd_nxt + 65535 + 2;
if (isn == 0)
isn++;
TCP_SKB_CB(skb)->tcp_tw_isn = isn;
return TCP_TW_SYN; // Allow reuse TIME_WAIT Reestablish the connection of quads
}
if (!th->rst) {
// If the timestamp wraps around , Or the message contains ack, Will TIMEWAIT The duration of the state is extended again
if (paws_reject || th->ack)
inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN,
TCP_TIMEWAIT_LEN);
// return TCP_TW_ACK, Send last ACK
return TCP_TW_ACK;
}
inet_twsk_put(tw);
return TCP_TW_SUCCESS;
}
If both sides enable TCP Timestamp mechanism , Would pass tcp_paws_reject() Function to determine whether the timestamp has been wrapped , That is to say 「 Timestamp of the currently received message 」 Is it greater than 「 Timestamp of the last received message 」:
- If it is greater than , It means that there is no time stamp detour , The function returns false.
- If it is less than , This indicates that a timestamp wrap has occurred , The function returns true.
You can see from the source code , When I received SYN After package , If it's time to SYN The timestamp of the packet did not wrap around , That is, the timestamp is incremented , also SYN The serial number of the package did not wrap around , That is to say SYN The serial number of 「 Greater than 」 Next expected serial number . Will initialize a serial number , Then return TCP_TW_SYN, Then reuse the connection , Just skip 2MSL And turn into SYN_RECV state , Then you can establish the connection process .
If neither side is enabled TCP Timestamp mechanism , Just judge SYN Does the serial number of the package wrap around , If SYN The serial number of is greater than the next expected serial number , You can skip 2MSL, Reuse the connection .
If SYN The bag is illegal , It will return TCP_TW_ACK, Then it will send the same... As the last time ACK Give each other .
stay TIME_WAIT state , received RST Will you disconnect ?
I left a question ahead , be in TIME_WAIT State connection , received RST Will you disconnect ?
Will it disconnect , Key points net.ipv4.tcp_rfc1337 This kernel parameter ( The default is 0):
- If this parameter is set to 0, received RST The message will end in advance TIME_WAIT state , Release the connection .
- If this parameter is set to 1, Will lose RST message .
The source code processing is as follows :
enum tcp_tw_status
tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
const struct tcphdr *th)
{
....
//rst The timestamp of the message does not wrap around
if (!paws_reject &&
(TCP_SKB_CB(skb)->seq == tcptw->tw_rcv_nxt &&
(TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq || th->rst))) {
// Handle rst message
if (th->rst) {
// Don't turn this option on , When I received RST It will be recycled immediately tw, But there are risks
if (twsk_net(tw)->ipv4.sysctl_tcp_rfc1337 == 0) {
kill:
// Delete tw Timer , And release tw
inet_twsk_deschedule_put(tw);
return TCP_TW_SUCCESS;
}
} else {
// take TIMEWAIT The duration of the state is extended again
inet_twsk_reschedule(tw, TCP_TIMEWAIT_LEN);
}
...
return TCP_TW_SUCCESS;
}
}
TIME_WAIT Status received RST Message and release the connection , This is tantamount to skipping 2MSL Time , There are still risks .
sysctl_tcp_rfc1337 This parameter is in rfc 1337 From the document , The purpose is to avoid because TIME_WAIT Status received RST Message and skip 2MSL Time for , Skip... Is also given in the document 2MSL What are the potential problems with time .
TIME_WAIT The reason why the state should last 2MSL Time , There are two main purposes :
- Prevent data in historical connections , Received by the connection error of the following same quadruple ;
- Guarantee 「 Passive close connection 」 On the side of , Can be properly closed ;
Detailed why to design TIME_WAIT state , I have detailed instructions in this article : If TIME_WAIT The state duration is too short or there is no , What's the problem ?
although TIME_WAIT The state lasts a little longer , Looks very unfriendly , But it's designed to avoid chaos .
《UNIX Network programming 》 One book says :TIME_WAIT It's our friend , It helps us , Don't try to avoid this state , It's about figuring it out .
therefore , Personally, I think it will net.ipv4.tcp_rfc1337 Set to 1 It will be safer .
summary
stay TCP During normal waving , be in TIME_WAIT State connection , Received the same quadruple SYN What happens after ?
If both sides turn on the timestamp mechanism :
- If the client's SYN Of 「 Serial number 」 Than the server 「 Expect the next received serial number 」 want Big , also SYN Of 「 Time stamp 」 Than the server 「 Timestamp of the last message received 」 want Big . Then the quad connection will be reused , skip 2MSL And turn into SYN_RECV state , Then you can establish the connection process .
- If the client's SYN Of 「 Serial number 」 Than the server 「 Expect the next received serial number 」 want Small , perhaps SYN Of 「 Time stamp 」 Than the server 「 Timestamp of the last message received 」 want Small . Then it will Reply to the fourth wave ACK message , When the client receives , I found that I didn't expect to receive the confirmation number , Just go back RST The message is sent to the server .
stay TIME_WAIT state , received RST Will you disconnect ?
- If
net.ipv4.tcp_rfc1337Parameter is 0, End ahead of time TIME_WAIT state , Release the connection . - If
net.ipv4.tcp_rfc1337Parameter is 1, Will lose the RST message .
End !









