What you should know about the exit of the TCP connection.... (Part 1)

foreword

insert image description here

Ok, this picture is familiar (if not, then you may not be suitable for reading this blog post). The normal whole process is relatively simple, but in real life, life is not always smooth, and abnormal situations still need to be considered from time to time.

Ok, today I will summarize some abnormalities (especially abnormal exit) in the whole communication process of tcp/ip in socket programming.

Since there are many situations to be discussed, it is a bit chaotic. For the sake of convenience and clarity, I intend to follow the process from top to bottom for analysis. Therefore, a small modification has been made to the above diagram.

insert image description here

Note that some abnormal situations below include several steps (circles) in the above figure, so it is not easy to divide, so the stages below are only roughly distinguished.


Not much nonsense, let's ride the horse and let's go.



1. Possible exceptions during connection establishment

For the tcp connection established using socket, in addition to the process described in the above figure, there are some auxiliary processes, such as binding ip and port number, etc., this process may also cause errors, this situation is static The situation is relatively simple and will not be considered here.

The establishment of a serious connection (beginning of data interaction) starts from connect, and this stage may be abnormal in ①②③ in the above figure.

1.1 Abnormalities in stage ① and ②: the server port is not opened

In the first phase of client connect, the kernel (the kernel of the client) will send a connection establishment request (send SYN) to the server. Return a RST section. After the client kernel receives it, knowing that an exception has occurred, it will return to the upper layer Connection refused; as shown in the figure below


insert image description here

You can understand it by default, (* ^ ▽ ^ *)

1.2 Abnormalities in the ①② stage: the client waits for the ACK to time out

This kind of situation is most classic and generally occurs in non-blocking connect, which is relatively rare. There is a description in [1], but it is not very accurate.

The specific scenario is this: the client sets up a non-blocking connect connection and sets a timeout. In this way, after the client sends the SYN segment, if it does not receive the ACK+SYN from the server within the set timeout period, the client's connect will immediately return an EINPROGRESS (the connection at the time of blocking will not return until it succeeds or fails. ). But note that if the client does not do special processing (such as closing the connection), the kernel will continue the TCP three-way handshake.

The figure below closes the program after connect returns EINPROGRESS. The second SYN is the SYN+ACK sent by the server (it has timed out); the third RST is that I closed the descriptor in the program, and then sent by the client kernel RST (as a response to the last SYN+ACK: I have closed the socket because of a timeout, and the server is still waiting there, no matter what, I have to give him a reply, RST abnormal reply is also a reply)
insert image description here

The picture below shows that after the connect timeout, I did not close the socket immediately, and the three-way handshake continued.
insert image description here

1.3 Abnormalities in the ②③ stage: the server waits for ACK timeout

insert image description here

This is the famous SYN Flood attack. The basic principle is that in the third phase of the handshake, if the server wants to wait for the client's ACK. If the client does not send the ACK for a long time, the server will retry, and the server will discard the unfinished ACK if the retry exceeds a certain number of times (or exceeds a certain time, that is, SYN Timeout, generally 30s -2 min). connect.

If a malicious client continues to forge TCP connection requests (without sending the third-stage ACK), then the server load will be quite large, resulting in increased access delay for normal use, which is the SYN Flood attack on the server.

1.4 Abnormality in stage ③: server-side accept exception

insert image description here

This situation describes that the client and the server establish a connection, but before the server prepares to accept the connection from the connection queue, the client sends a disconnection process (such as a process crash) for various reasons, resulting in The client sends a RST segment , so what happens on the server?


I describe this situation vividly as: I clearly agreed to hold hands together, but when I was about to extend my hand, you turned your head away!


For this situation, different system kernels may handle it differently. There are common processing methods as follows (from [3]):
insert image description here


I did an experiment under linux, and found that accept on linux will not report an error, but when reading and writing the obtained socket, an error "Connection reset by peer" will be reported.

In [4], there is an explanation of this phenomenon in linux:

insert image description here


The experimental code and corresponding screenshots of the results are attached here.

//客户端
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdint.h>
#include <assert.h>
#include <fcntl.h>
#include <string.h>
#include <bits/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>

const char* ip = "x.x.x.x";
uint16_t port = 9999;

int main()
{
    
    
    int sock_fd = socket(PF_INET, SOCK_STREAM, 0);

    struct sockaddr_in sock_addr;
    memset(&sock_addr, 0, sizeof(sock_addr));
    sock_addr.sin_family = AF_INET;
    sock_addr.sin_port = htons(port);
    inet_pton(AF_INET, ip, &(sock_addr.sin_addr));

    int ret = connect(sock_fd, (sockaddr*)&sock_addr, sizeof(sock_addr));

    if(ret < 0)
    {
    
    
        printf("%s\n", strerror(errno));
    }

    struct linger my_linger;
    memset(&my_linger, 0, sizeof(my_linger));
    my_linger.l_onoff = 1;
    my_linger.l_linger = 0;

    setsockopt(sock_fd, SOL_SOCKET, SO_LINGER, &my_linger, sizeof(my_linger));

    close(sock_fd);

    return 0;
}

//服务器端
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdint.h>
#include <assert.h>
#include <fcntl.h>
#include <string.h>
#include <bits/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>

const char* ip = "0.0.0.0";
uint16_t port = 9999;
char buff[1024];

void make_sock_noblocking(int sock_fd)
{
    
    
    int flags = fcntl(sock_fd, F_GETFL, 0);
    flags |= O_NONBLOCK;
    fcntl(sock_fd, F_SETFL, flags);
}

int main()
{
    
    
    int listen_fd = socket(PF_INET, SOCK_STREAM, 0);

    struct sockaddr_in sock_addr;
    memset(&sock_addr, 0, sizeof(sock_addr));
    sock_addr.sin_family = AF_INET;
    sock_addr.sin_port = htons(port);
    inet_pton(AF_INET, ip, &(sock_addr.sin_addr));

    int optval = 1;
    setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR,
               (const void *)&optval , sizeof(int));
    int ret = bind(listen_fd, (sockaddr*)&sock_addr, sizeof(sock_addr));

    listen(listen_fd, 1024);

    make_sock_noblocking(listen_fd);

    sleep(10);

    struct sockaddr_in client_addr;
    memset(&sock_addr, 0, sizeof(client_addr));
    socklen_t len = sizeof(client_addr);
    int conn_fd = accept(listen_fd, (sockaddr*)&client_addr, &(len));

    printf("%d--------%s\n", conn_fd, strerror(errno));

    int read_bytes = read(conn_fd, buff, sizeof(buff));

    printf("%d %s\n", read_bytes, strerror(errno));

    return 0;
}


The screenshot of the experiment is as follows:
Client:
insert image description here

Service-Terminal:
insert image description here




enen...
I did a little research later, if the client does not send RST (abnormally close the connection), but FIN (normally close the connection) when the client exits, what will happen?

you guess…

I did an experiment, the connection is normal, and the socket can be obtained, but the read will return 0 (probably the other party's connection has been closed). As shown below,

Service-Terminal:
insert image description here

client:
insert image description here

Service-Terminal:
insert image description here


reference

[1], TCP/IP Detailed Explanation – Several Situations of Receiving RST Response
[2], SYN Flood Attack Principle and Prevention
[3], TCP Exception Handling (Connection Termination Before Accept Returns) and SO_LINGER Option
[4], Accept Under Linux Previously abnormally terminated connection issues?

Guess you like

Origin blog.csdn.net/plm199513100/article/details/113995894
Recommended