Implementation of TCP penetration Nat

Source: Internet
Author: User
Tags htons
1. TCP penetration principle:

We assume that there are two clients a and B behind two different LAN, and the LAN where AB is located is connected to the Internet through a router. There is a server s on the Internet.
At present, AB cannot directly send information with the other party, and AB does not know the real IP address and port of the other party on the Internet, the vro of the LAN where AB is located only allows information sent internally to the outside to pass through. For messages sent by B directly to a's vro, the routing will regard it as "untrusted" and directly discard it.
To achieve direct AB communication, you must perform the following three steps: A first connects to the server s on the Internet and sends a message (for a non-connection protocol such as UDP, you can directly send a message through the initial session ), in this way, s obtains the actual terminal (IP address and port number of the message sending) of a on the Internet ). Then B follows the same steps, and s will know the terminals of AB on the Internet (this is "drilling holes "). Then, s tells Client A and client B the actual terminal on the Internet, that is, s tells client B's session terminal, and s tells Client A's session terminal. In this way, after AB knows the actual terminal of the other party, it 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 access ).

2. Program ideas:

1: Start the server and listen to port 8877
2: when the client is started for the first time (called Client1) and connected to the server, the server returns the string first, which identifies this as Client1. At the same time, the server will record this client (after conversion) IP address and port.
3: the second time the client (called Client2) is started, the server connects to the server, and the server returns its own sending port (called port2), as well as the IP address and port of Client1 (converted.
4: The server then sends the Client1 request to return the IP address and port of Client2 (after conversion), and then disconnects the two clients (at this time, all the work of the server has been completed)
5: Client2 tries to connect to Client1. This time it will certainly fail, but it will leave a record on the vro to help Client1 successfully penetrate, connect to itself, and then set port2 port as reusable port, and listen to Port 2.
6: Client1 tries to connect to Client2. The previous attempts may fail because the penetration has not been successful. If the connection fails for 10 times, it indicates that the penetration fails (probably not supported by hardware). If the penetration succeeds, the system sends Hello, world
7. If Client1 continuously sends message: Hello, world, and Client2 Recv message: Hello, world, the experiment is successful. Otherwise, the experiment fails.

3. Statement

1: This program is just a demo, so there must be a lot of imperfections. Please forgive me.
2: In many networks, this program cannot be successful. It may be a hardware problem (after all, not every vro supports penetration) or a problem with my program, if you have any comments or suggestions, please leave a message or send me an email (Email: aa1080711@163.com)

4. Code above:

Server:

/* File: Server. CPS: the first client connected to the server, called Client1, and the second Client Connected to the server is called Client2. The function of this server is: 1: for Client1, it returns "first ", after the Client2 connection, send the converted IP address and port of Client2 to Client1; 2: For Client2, it returns the converted IP address and port of Client1 and its own port, and then disconnect from them. */# Include <stdio. h> # include <unistd. h> # include <signal. h> # include <sys/socket. h> # include <fcntl. h> # include <stdlib. h> # include <errno. h> # include <string. h> # include <ARPA/inet. h> # define maxline 128 # define serv_port 8877 // a fatal error occurs. Exit the program void error_quit (const char * Str) {fprintf (stderr, "% s", STR ); // if an error code is set, enter the cause of the error if (errno! = 0) fprintf (stderr, ": % s", strerror (errno); printf ("\ n"); exit (1);} int main (void) {int I, res, cur_port; int connfd, firstfd, listenfd; int COUNT = 0; char str_ip [maxline]; // The cached IP address char cur_inf [maxline]; // The current connection information [IP + port] char first_inf [maxline]; // The information of the first link [IP + port] char buffer [maxline]; // temporarily send the buffer socklen_t clilen; struct sockaddr_in cliaddr; struct sockaddr_in servaddr; // create a socket for listening to TCP protocol listenfd = socket (af_inet, sock_stream, 0); memset (& servaddr, 0, sizeof (servaddr); servaddr. sin_family = af_inet; servaddr. sin_addr.s_addr = htonl (inaddr_any); servaddr. sin_port = htons (serv_port); // link the socket and socket address structures res = BIND (listenfd, (struct sockaddr *) & servaddr, sizeof (servaddr )); if (-1 = res) error_quit ("BIND error"); // start listening port res = listen (listenfd, inaddr_any); If (-1 = res) error_quit ("Listen error"); While (1) {// receive connection connfd = accept (listenfd, (struct sockaddr *) & cliaddr, & clilen) from the client ); if (-1 = connfd) error_quit ("Accept error"); inet_ntop (af_inet, (void *) & cliaddr. sin_addr, str_ip, sizeof (str_ip); count ++; // For the first link, store its IP + port to first_inf, // establish a long link with it, and then send it the string 'first', if (COUNT = 1) {firstfd = connfd; cur_port = ntohs (cliaddr. sin_port); snprintf (first_inf, maxline, "% S % d", str_ip, cur_port); strcpy (cur_inf, "first \ n"); write (connfd, cur_inf, strlen (cur_inf) + 1);} // For the second link, send its IP address + port to the first link, // return the information of the first link and its own port to itself, // then disconnect the two links and reset the counter else if (COUNT = 2) {cur_port = ntohs (cliaddr. sin_port); snprintf (cur_inf, maxline, "% S % d \ n", str_ip, cur_port); snprintf (buffer, maxline, "% S % d \ n", first_inf, cur_port); write (connfd, buffer, strlen (buffer) + 1); write (firstfd, cur_inf, strlen (cur_inf) + 1); close (connfd ); close (firstfd); Count = 0;} // if the program runs here, elseerror_quit ("Bad required");} return 0 ;}

Client:

/* File: client. CPS: the first client connected to the server, called Client1, and the second Client Connected to the server is called Client2. The function of this program is to connect to the server first, based on the server's return, it is determined whether it is Client1 or Client2. If it is Client1, it obtains the IP and port of Client2 from the server, connects to Client2, if it is Client2, it will get the IP address and port of Client1 from the server and the converted port of itself. After trying to connect Client1 (this operation will fail ), then listen Based on the port returned by the server. In this way, point-to-point communication can be performed between two clients. */# Include <stdio. h> # include <unistd. h> # include <signal. h> # include <sys/socket. h> # include <fcntl. h> # include <stdlib. h> # include <errno. h> # include <string. h> # include <ARPA/inet. h> # define maxline 128 # define serv_port 8877 typedef struct {char IP [32]; int port ;}server; // a fatal error occurs, exit the program void error_quit (const char * Str) {fprintf (stderr, "% s", STR); // if an error code is set, enter the error cause if (errno! = 0) fprintf (stderr, ": % s", strerror (errno); printf ("\ n"); exit (1);} int main (INT argc, char ** argv) {int I, res, port; int connfd, sockfd, listenfd; unsigned int value = 1; char buffer [maxline]; socklen_t clilen; struct sockaddr_in servaddr, sockaddr, connaddr; server other; If (argc! = 2) error_quit ("using :. /client <IP address> "); // create a socket sockfd = socket (af_inet, sock_stream, 0) for the link (master server); memset (& sockaddr, 0, sizeof (sockaddr); sockaddr. sin_family = af_inet; sockaddr. sin_addr.s_addr = htonl (inaddr_any); sockaddr. sin_port = htons (serv_port); inet_ton (af_inet, argv [1], & sockaddr. sin_addr); // set the port to be reused setsockopt (sockfd, sol_socket, so_reuseaddr, & Value, sizeof (value); // connect to the master server res = connect (sockfd, (struct sockaddr *) & sockaddr, sizeof (sockaddr); If (RES <0) error_quit ("Connect error "); // read the information from the master server. Res = read (sockfd, buffer, maxline); If (RES <0) error_quit ("read error"); printf ("get: % s ", buffer); // if the server returns first, it indicates that it is the first client if ('F' = buffer [0]) {// read the IP address of the second client from the server + portres = read (sockfd, buffer, maxline); sscanf (buffer, "% S % d", other. IP, & Other. port); printf ("FF: % S % d \ n", other. IP, other. port); // create the socket connfd = socket (af_inet, sock_stream, 0); memset (& connaddr, 0, sizeof (connaddr); connaddr. sin_family = af_inet; connaddr. sin_addr.s_addr = htonl (inaddr_any); connaddr. sin_port = htons (Other. port); inet_ton (af_inet, other. IP, & connaddr. sin_addr); // try to connect to the second client. The previous attempts may fail because the penetration has not been successful. // if the connection fails for 10 times, it turns out that penetration failed (probably not supported by hardware) while (1) {static Int J = 1; Res = connect (connfd, (struct sockaddr *) & connaddr, sizeof (connaddr); If (RES =-1) {If (j> = 10) error_quit ("can't connect to the other client \ n "); printf ("Connect error, try again. % d \ n ", J ++); sleep (1);} else break;} strcpy (buffer," Hello, world \ n "); // after the connection is successful, send a hello, worldwhile (1) {res = write (connfd, buffer, strlen (buffer) + 1) to the other party (Client 2) every second ); if (RES <= 0) error_quit ("write error"); printf ("Send message: % s", buffer); sleep (1 );}} // The behavior of the second client else {// obtain the portsscanf (buffer, "% S % d", other. IP, & Other. port, & Port); // create socket sockfd = socket (af_inet, sock_stream, 0) for TCP protocol; memset (& connaddr, 0, sizeof (connaddr); connaddr. sin_family = af_inet; connaddr. sin_addr.s_addr = htonl (inaddr_any); connaddr. sin_port = htons (Other. port); inet_ton (af_inet, other. IP, & connaddr. sin_addr); // set port reuse setsockopt (sockfd, sol_socket, so_reuseaddr, & Value, sizeof (value); // try to connect to client 1, it will certainly fail, but it will leave a record on the vro, // to help client 1 successfully penetrate, connect to its own res = connect (sockfd, (struct sockaddr *) & connaddr, sizeof (connaddr); If (RES <0) printf ("Connect error \ n"); // create a socket for listening listenfd = socket (af_inet, sock_stream, 0 ); memset (& servaddr, 0, sizeof (servaddr); servaddr. sin_family = af_inet; servaddr. sin_addr.s_addr = htonl (inaddr_any); servaddr. sin_port = htons (port); // set port reuse setsockopt (listenfd, sol_socket, so_reuseaddr, & Value, sizeof (value )); // link the socket and socket address structures. Res = BIND (listenfd, (struct sockaddr *) & servaddr, sizeof (servaddr); If (-1 = res) error_quit ("BIND error"); // start listening to ports res = listen (listenfd, inaddr_any); If (-1 = res) error_quit ("Listen error "); while (1) {// receive connection connfd = accept (listenfd, (struct sockaddr *) & sockaddr, & clilen) from client 1; if (-1 = connfd) error_quit ("Accept error"); While (1) {// cyclically read information from client 1 res = read (connfd, buffer, maxline); If (RES <= 0) error_quit ("read error"); printf ("Recv message: % s", buffer);} Close (connfd) ;}} return 0 ;}

5. Running example:

(First Terminal)
Qch @ qch ~ /Program/tcode $ GCC server. C-O Server
Qch @ qch ~ /Program/tcode $./Server &
[1] 4688
Qch @ qch ~ /Program/tcode $ GCC client. C-O client
Qch @ qch ~ /Program/tcode $./client localhost
Get: first
FF: Wagner. 0.0.1 38052
Send message: Hello, world
Send message: Hello, world
Send message: Hello, world
.................

The second terminal:
Qch @ qch ~ /Program/tcode $./client localhost
Get: Wagner. 0.0.1 38073 38074
Connect Error
Recv message: Hello, world
Recv message: Hello, world
Recv message: Hello, world
..................

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.