TCP Self Connection Problem

TCP connection can be established by SYN segmentation initiated by both ends to the other party at the same time. At the same time, the established connection must meet one condition. After SYN connection request is issued by both TCP ends, a SYN connection request is still received, and the SYN received is exactly from the end that sent SYN to request connection.So is there a situation like this? A TCP end issues a SYN segment to itself, and the connection requested by the SYN segment is exactly the TCP end itself, which meets the condition of “SYN request is received at the same time as SYN request, and the SYN received happens to be from the end of the requesting connection”. This situation is real and is called TCP self-connection. The existence of self-connectivity often causes inexplicable problems and hard-to-reproduce failures and software bugs.

Connection Sequence

The segments interaction sequence of TCP connection at the same time,

Now we make some modification to the diagram and compare it with the previous one?Instead of [1.syn k], [1.syn n] is sent to itself other than to the other endpoint, here n equals to k.

After the connection is established, the connection situation is as follows:

When the connection is disconnected, the interaction sequence is similar to the establishment of the connection.

An example of self connection

Now we reproduce the self-connection senario with the following code, only client.c is required here.

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//client.c
#include "lib/unp.h"

int main(int argc, char **argv)
{
//初始化工作
int sockfd = 0; //Client进程的Socket文件描述符
int dstport = 0; //Server进程监听TCP端口号
int srcport = 0; //Client进程指定本地TCP端口号
char response[MAXLINE + 1]; //Server进程返回的响应内容
char request[] = "request,hostname\r\n"; //Client进程发出的请求消息
struct sockaddr_in servaddr; //用于存储Server进程所在主机的IP地址及TCP端口号

bzero(&servaddr, sizeof(servaddr));
bzero(response, MAXLINE + 1);

//设置将要连接服务器进程的IP地址和TCP端口号
sscanf(argv[3], "%d", &dstport);
servaddr.sin_family = AF_INET;
Inet_pton(AF_INET, argv[2], &servaddr.sin_addr);
servaddr.sin_port = htons((uint16_t) dstport);

//创建sockfd,AF_INET表示IPv4,SOCK_STREAM表示TCP
sockfd = Socket(AF_INET, SOCK_STREAM, 0);

//强制绑定客户端端口号到sockfd
sscanf(argv[1], "%d", &srcport);
struct sockaddr_in clientaddr;
bzero(&clientaddr, sizeof(clientaddr));
clientaddr.sin_family = AF_INET;
clientaddr.sin_port = htons((uint16_t)srcport);
Bind(sockfd, (SA *) &clientaddr, sizeof(clientaddr));

//发起连接请求, 关联sockfd和Server进程的IP地址,TCP端口号
Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));

//发送请求消息
Write(sockfd, (char*) request, strlen(request));

//等待响应消息
Readline(sockfd, response, sizeof(response));

printf("%s\n", response);

//关闭sockfd,通知服务进程通信结束
Close(sockfd);

//进程结束
exit(0);
}

Self-connection establishment

On the host 10.22.5.3, execute client with parameters argv1 55555,argv2 10.22.5.3,argv3 55555,

1
2
toto@guru:~$ client 55555 10.22.5.3 55555
request,hostname

Single step run the client to function Connect() with Gdb, check the TCP connection status,

1
2
toto@guru:~$ netstat -ant | grep 55555
tcp 0 0 10.22.5.3:55555 10.22.5.3:55555 ESTABLISHED

When the instance runs, Wireshark is used to retrieve TCP segment data [1.syn n], [2.syn n, ACK k+1], and the details are as follows, from 10.22.5.3:55555 to 10.22.5.3:55555 to initiate a SYN connection request. ISN for 787485307. Initiate SYN, ACK from 10.22.5.3:55555 to 10.22.5.3:55555. ACK for 787485308.

Self-connection disconnect

Running until the end of the process, Wireshark is used to obtain TCP segment data [1.fin n], and the details of [2.ack n+1] are as follows:

Check the TCP connection status,

1
2
toto@guru:~$ netstat -ant | grep 55555
tcp 0 0 10.22.5.3:55555 10.22.5.3:55555 TIME_WAIT

Avoid self-connection problems

TCP self-connection occurs because both the client and the server are located on the same host, and the server port is within the scope of the random port used by the client system, and the client frequently establishes TCP connection. For example, the current host provides the client with a temporary port range of [32768,61000], which may cause TCP self-connection when the port within this range is selected as the service port. Therefore, attention should be paid to the design.

1
2
#View temporary port ranges available under Linux
cat /proc/sys/net/ipv4/ip_local_port_range