当前位置:网站首页>At time_ What happens to TCP connections in wait status after SYN is received?

At time_ What happens to TCP connections in wait status after SYN is received?

2022-06-09 07:50:00 Xiaolin coding

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 :

 picture

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 :

 picture

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 :

 picture

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 :

 picture

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 :

  1. After receiving the message , Would call __inet_lookup_skb() Function to find the corresponding sock structure ;
  2. If the status of the connection is TIME_WAIT, Will jump to do_time_wait Handle ;
  3. 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, 0NULL);

  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_rfc1337 Parameter is 0, End ahead of time TIME_WAIT state , Release the connection .
  • If net.ipv4.tcp_rfc1337 Parameter is 1, Will lose the RST message .

End !

原网站

版权声明
本文为[Xiaolin coding]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/03/202203021356115926.html