Analysis and implementation of the TCP three-way handshake

 

A, TCP packet format

        TCP packet format Figure:

 

        There are several fields describes the figure above:
        (1) Reference: Seq number, representing 32 bits, used to identify the byte stream from the TCP source to the destination of the transmission, which is labeled when the sender sends data.
        (2) the acknowledgment number: Ack number, accounting for 32, when only the ACK flag bit is 1, the acknowledgment number field is valid, Ack = Seq + 1.
        (3) Flags: a total of six, i.e. URG, ACK, PSH, RST, SYN, FIN , and specific meanings are as follows:
                (A) the URG: Urgent Pointer (urgent pointer) effective.
                (B) ACK: acknowledgment number is valid.
                (C) PSH: recipient should be the message to the application layer as soon as possible.
                (D) RST: reset the connection.
                (E) SYN: initiate a new connection.
                (F) FIN: releasing a connection.

Second, the mechanism and process of the three-way handshake

        The so-called three-way handshake (Three-Way Handshake) namely the establishment of a TCP connection, refers to the establishment of a TCP connection, the client and the server needs to send a total of three packages to confirm the establishment of the connection. In socket programming, this process is triggered by the execution client connect, the entire process as shown below:



Why do we need three-way handshake:
connection request to delay the assumption client, client will issue a second connection request, the server-side reply is to establish a connection for communication. Wait until the end of the communication, the connection is closed, then it is possible for the first time before the connection request to the server side, then the time after the server reply message, it will consider the connection has been established, but the client-side view, did not initiate the connection request ( When the connection is retried, the communication has been completed and close the connection), it will ignore the message server side, it will not send data to this link. This time for the server end, it will be because maintaining this link which led to a waste of resources.

Three-way handshake process is detailed as follows:

        (1) The first handshake: Client SYN flag bit is set to 1, a randomly generated value seq = J, and the packet is sent to the Server, Client enters the SYN_SENT state, waiting for acknowledgment Server.
        (2) The second handshake: Server receives the packet data from the flag bit SYN = 1 know Client requests to establish a connection, Server SYN and ACK flag bit are set to 1, ack = J + 1, a randomly generated value seq = K, and transmits the data packet to acknowledge a connection request to the Client, Server enters SYN_RCVD state.
        (3) third handshake: the Client receives acknowledgment, checking whether the ack J + 1, ACK is 1, then if the correct ACK flag is set to 1, ack = K + 1, and the data packet to Server, Server checks whether the ack K + 1, ACK is 1, if correct, the connection is established, Client and Server enters eSTABLISHED state, complete the three-way handshake, then you can begin to transfer data between Client and Server.
        
About SYN attack:
                In the three-way handshake process, Server after sending the SYN-ACK, before receiving the ACK TCP connection is called the Client connection half (half-open connect), Server SYN_RCVD state at this time, when the ACK is received, Server into ESTABLISHED status. Client SYN attack is a large number of forged IP address does not exist in a short time, and continue to send Server SYN packet, Server reply to the confirmation packet, and wait for confirmation of the Client, since the source address does not exist, therefore, Server requires constant weight hair until the timeout, the forged SYN packet will take up production time is not connection queue, leading to the normal SYN requests because the queue is full are discarded, thereby causing network congestion or even system failure. SYN attack a typical DDOS attack detection SYN attack is very simple, that is, when a large number of semi-connected state Server and the source IP address is random, it can be concluded that the attack was a SYN, use the following command allows the current:
                #netstat -nap | grep SYN_RECV

The entire TCP state schematically as follows:

 

Three, Linux in the process of implementing TCP handshake

  When Application Programming Linux If set to non-blocking mode, the connection, connect return immediately after sending the SYN packet -EINPROGRESS, represents the operation is in progress; subsequent application may do some further treatment after return to connect, and finally to select the function in capture socket connection, read and write, to trigger abnormal event related operation, let's take a look at the kernel associated implementation:

 

First, the client support    

  client sends two packets, a SYN packet, a response ACK packet to the server.      

     client function in the chain: connect -> sys_connect-> inet_stream_connect-> tcp_connect ...
     see section snippet inet_stream_connect implemented:

switch (sock->state) {
     ...        
                /*此处调用tcp_connect函数发送SYN包*/
       err = sk->prot->connect(sk, uaddr, addr_len);       
  if (err < 0)  //出错则退出
   goto out;
       sock->state = SS_CONNECTING;

  /* 此处仅设置socket的状态为SS_CONNECTING表示连接状态正在处理;
   * 不同之处在于非阻塞情况下,返回值设置为-EINPROGRESS表示操作正在处理
   * 而阻塞式情况则在获得ACK包后将返回值置为-EALREADY.
   */
  err = -EINPROGRESS;
  break;
      }
     
      timeo = sock_sndtimeo(sk, flags&O_NONBLOCK); //注意,如果此时设置了非阻塞选项,则timeo返回0
        //如果socket对应的sock状态是SYN包已发送或收到SYN包并发送了ACK包,并等待对端发送第三此的ACK包
 if ((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) {
  /* 错误返回码err前面已经设置 */
  if (!timeo || !inet_wait_for_connect(sk, timeo))
  /*注意上面所判断的2中情况,1、如果是非阻塞模式,则!timeo为1,则直接跳到out返回-EINPROGRESS结束connect函数
    2、若为阻塞模式,则在inet_wait_for_connect函数中通过schedule_timeout函数放弃cpu控制权睡眠,等待服务器端
    发送ACK响应包后被唤醒继续处理。如果没有异常出现,则置socket状态为SS_CONNECTED,表示连接成功,正确返回
  */
   goto out;
  
  err = sock_intr_errno(timeo);
  if (signal_pending(current)) /*处理未决信号*/
   goto out;
 }
 ...
 sock->state = SS_CONNECTED;
 err = 0;
     out:
 release_sock(sk);
 return err;

 


    上面的描述有一个问题:对服务器的响应ACK包是什么时候发送的?对于非阻塞模式,应该是应用处理过程中的某个异步时间;对于阻塞模式,则是在inet_wait_for_connect函数中睡眠时处理。即网卡在收到对方的ack包后,上传给对应的socket时发送服务器的响应ACK包,函数调用链为:netif_rx-->net_rx_action-->...(IP层处理)-->tcp_v4_rcv-->tcp_v4_do_rcv-->tcp_rcv_state_process-->tcp_rcv_synsent_state_process-->tcp_send_synack-->tcp_transmit_skb...
    发送SYN包后,socket对应的sock的状态变成TCPF_SYN_SENT,网卡收到服务器的ack传到tcp层时,根据TCPF_SYN_SENT状态,做相关判断后再发送用于第三次握手的ack包。至此,将socket的状态改为连接建立,即TCP_ESTABLISHED。 具体的代码大家可以根据我提供的函数调用链查看。
    注意,以TCPF_前缀开头的状态都表示是中间状态,而已TCP_为前缀的状态才是socket的一个相对稳定的状态。     
 

二、服务器端支持

    服务器端此时必须是监听状态,则其函数调用链为:
          netif_rx-->net_rx_action-->...(IP层处理)-->tcp_v4_rcv-->tcp_v4_do_rcv-->
          tcp_rcv_state_process-->tcp_v4_conn_request-->tcp_v4_send_synack...
    在tcp_v4_conn_request,中部分代码如下:     

    case TCP_LISTEN:
  if(th->ack) /*监听时收到的ack包都丢弃?*/
   return 1;

  if(th->syn) {/*如果是SYN包,则调用tcp_v4_conn_request*/
   if(tp->af_specific->conn_request(sk, skb) < 0)
    return 1;
    ...

Guess you like

Origin www.cnblogs.com/z501938568/p/12090866.html