[Turn] nat penetration principle

[Turn] nat penetration principle
 
 

For a long time, when it comes to NAT penetration, many people will be told to use UDP hole punching technology. Basically no one will tell you how to use TCP protocol to penetrate (even some people will directly tell you that TCP protocol cannot be penetrated. Transparent). However, it is well known that UDP is a connectionless datagram protocol. To use it, you must maintain the integrity of the data packets sent and received. This often greatly increases the complexity of the program, and some programs must use TCP for some reasons. Protocol, this often makes some people who develop TCP network programs "talk about penetration". So, is it impossible to achieve penetration using the TCP protocol? The answer is of course no: TCP protocol can not only achieve NAT penetration, but it is even simpler than UDP penetration.

To understand how to use TCP to penetrate NAT, we must first look at how to use UDP to penetrate NAT.

We assume that there are two clients A and B behind two different LANs, and the LAN where AB is connected to the Internet through a router. There is a server S on the Internet.

Now AB cannot directly send information to the other party. AB does not know the other party's real IP and port on the Internet. The router in the local area network where AB is located only allows information sent from inside to outside to pass. For a message sent by B directly to A's router, the route will consider it "untrusted" and discard it directly.

To achieve direct communication between AB, the following three steps must be performed: A first connects to the server S on the Internet and sends a message (for a connectionless protocol such as UDP, the message can be sent directly to the initial session), so that S gets A The actual terminal on the Internet (the IP and port number that sends the message). Then B performs the same steps, and S knows AB's terminal on the Internet (this is "hole punching"). Then S tells A and B the actual terminals of the other clients on the Internet, that is, S tells A's client B's conversation terminal, and S tells B's client A's conversation terminal. In this way, after AB knows the actual terminal of the other party, they can directly send messages through the actual terminal (because both parties have previously sent messages to the outside, there is already a message channel on the route that allows data to enter and exit).

There is no theoretical problem with using UDP to achieve the above three steps, because UDP is a connectionless protocol, which allows sockets to carry out "many-to-one" communication (that is, several sockets with different IP and port numbers can receive socket send messages). But there is a problem with TCP: In general, TCP socket does not allow to monitor and use the local port on the port where the connection has been established. In other words, when AB connects to server S, S tells the actual terminal of AB to the other party. The next step should be for AB to use the actual terminal of the other party for direct connection, but then you will find that the actual terminal of the other party is already occupied. (That is, the respective sessions connected to server S occupy the terminal), and cannot listen and connect at the same time. So many people come to the conclusion: TCP cannot achieve NAT penetration.

So the key to the problem becomes how to reuse a local terminal connected by TCP. This is not a protocol issue, but an API issue. Fortunately, all major operating systems support a specific TCP socket option-SO_REUSEADDR. This option allows multiple sockets to be bound to the same local terminal. When we create a socket, we only need to add this line:

setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &flag, len); //C++ does this

_Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, True)'This is vb.net easier

Knowing the above knowledge is easy to handle, let me talk about the penetration process of the TCP protocol:

The machine layout is still the same as above using UDP. Now suppose that client A wants to establish a TCP connection with client B.

First of all, AB establishes a connection with server S separately, and S records the actual Internet terminal of AB. Then S sends the actual terminal of the other party to AB. Then, from the port used when connecting from A and B to S, AB asynchronously calls the connect function to connect to the actual terminal of the other party (the terminal that S tells). At the same time, both parties are listening to the incoming connection on the same local port (or It is better to listen first, then connect). Since both parties have sent a connect request to each other (assuming that their SYN packets have passed through their own NAT), when the other connect request reaches the local listening port, the router will think that the request is part of the connect session just now. If it has been approved, the local listening port will respond with SYN-ACK and agree to connect. In this way, the point-to-point connection of TCP traversing NAT succeeds.

Guess you like

Origin blog.csdn.net/zhengjian1996/article/details/112936083