If there is no listen, can a TCP connection be established?

2023.03.11

If there is no listen, can a TCP connection be established?

In the process of TCP network communication, we all have the server call listen to monitor a certain port number first, then the client initiates a connection request to the server, and finally establishes a connection.

In the process of TCP network communication, we all have the server call listen to monitor a certain port number first, then the client initiates a connection request to the server, and finally establishes the connection.

So, is it possible to establish a TCP connection without one end listening?

For TCP, the establishment of a link is accomplished through a three-way handshake, and the process of the three-way handshake is completed by the kernel. Obviously, the three-way handshake application cannot interfere.

Therefore, we may think of using raw sockets to receive IP packets, and use the application layer to construct three-way handshake packets to complete the three-way handshake process, but this method will not work, because raw sockets receive IP packets from the peer When responding with a syn+ack message, the system will automatically respond to the peer end with a RST message to terminate the connection. This phenomenon has been analyzed in the original article and is not analyzed in this article. To realize the success of the three-way handshake of the socket, it is necessary to solve the problem that the system automatically responds to the RST message, such as filtering out the RST message through iptable.

In the three-way handshake of TCP, the reason why the client can find the corresponding socket after receiving the syn+ack message responded by the peer is because the socket is added to the hash table of tcp_hashinfo.ehash according to the port number when connecting middle. The original socket will automatically reply the RST message, but the socket is not added to the hash table, so the socket cannot be found.

Therefore, we can get that the establishment of the link can be completed as long as the socket cannot be found. Therefore, the establishment of the link can be completed by opening the socket at both ends at the same time, and one end does not need to listen.

Simultaneous connection

The test procedure is to bind each of the two machines to a local address and port number, and then send a connect request to the port bound to the opposite end at the same time. The specific example will not be posted.

In a simultaneous connection, both ends send SYN messages at the same time and enter the SYN_SENT state; when each end receives the SYN, the state changes to SYN_RCVD, sends the SYN and confirms the received SYN; when both ends receive the SYN and the corresponding ACK, the state changes to ESTABLISHED. The state transition process is as follows:

The above is that the two ends connect to each other to complete the establishment of the link. If the two ends are removed, we can also realize the IP and port number bound to the local end of the connect.

Use nc to test a TCP connection that connects itself

# nc 10.115.20.30 1234 -p 1234
# netstat -anp | grep 1234
tcp 0 0 10.115.20.30:1234 10.115.20.30:1234 ESTABLISHED 2050/nc
  • 1.
  • 2.
  • 3.

It can be seen from the above that the source port number is equal to the destination port number, and the establishment of the link is also completed.

# strace nc 10.115.20.30 1234 -p 1234
execve("/usr/bin/nc", ["nc", "10.115.20.30", "1234", "-p", " 1234"], [/* 31 vars */]) = 0
brk(NULL) = 0x23d4000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f213f394000

...

munmap(0x7f213f393000, 4096) = 0
open("/usr/share/ncat/ca-bundle.crt", O_RDONLY) = -1 ENOENT (No such file or directory)
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
bind(3, {sa_family=AF_INET, sin_port=htons(1234), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
//bind后直接就是connect,并没有进行listen
connect(3, {sa_family=AF_INET, sin_port=htons(1234), sin_addr=inet_addr("10.115.20.30")}, 16) = -1 EINPROGRESS (Operation now in progress)
select(4, [3], [3], [3], {10, 0}) = 1 (out [3], left {9, 999998})
getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
select(4, [0 3], [], [], NULL
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

From the tracking results, it can be seen that it connects itself (shares the same socket) to complete the establishment of the link.

Connecting yourself is just a special case of simultaneous connections.