I read an article in the "ziqingxing" friend blog about the implementation of a mini tool called "DuplexPipe. I didn't quite understand it at first. I read the open source code and wrote it in java, a jar package. Unfortunately, I don't know much about java, so I can't read it.
After thinking about it for a long time, I decided to write it in C language. The initial goal was to build a program that can connect to the internal network sub-host hidden behind NAT from the Internet. After writing for a day, there were about 300 lines, and the program was able to work, but the code was very bad, the structure is chaotic, and the idea is still masked.
The next day, I thought about the idea carefully and decided to simplify it according to the Unix idea, and only do one thing. As a result, the idea is clear and the tool is released.
The name is pf, short for port forwarding, that is, port forwarding. Specify the two ports A, B, and pf to constantly forward the data from A to B, and start A sub-process to do the opposite, and forward the data from B to. In this way, the two ports are connected, and the data can work in both directions at the same time, which is full-duplex.
There are two main options:
-L port-l specifies a local port, which will be listened on. Data can be forwarded when a connection arrives.
-C ip: port-c specifies a destination address, so the ip address and port number are required. Pf
Connect to this address. And forward data
There are four combinations:
Two-l ports A and B are specified to exchange data between A and B.
One-l, one-c. One passive connection, one active connection, and data exchange
Both-c instances are actively connected.
Example:
1. The forwarding port. If the web server is on port 8000 and it is not convenient to modify the port number, you can use pf:
$./Pf-c 8000-l 80
-C means to actively connect to the 8000 web server, and then listen on port 80 and exchange data between the two. If another user connects to port 80, it is like directly connecting to port 8000.
2. Connect to the host after NAT from the Internet:
If port 3389 is enabled on the Intranet host, run pf on the host first:
(Assume that the IP address of the Internet host is 12.34.56.78)
$./Pf-c 3389-c 12.34.56.78: 2000
Connect to port 3389 of the Local Machine and connect it to port 2000 of 12.34.56.78.
Next, run pf on the machine 12.34.56.78 on the Internet:
$./Pf-l 2000-l 5000
Accept the connection from the external header to port 2000 and connect the connection to port 5000.
In this case, you can use a client tool on an Internet host to connect to the local port 5000, which is equivalent to connecting to port 3389 of the Intranet host after NAT.
$ Tsclient local host 5000
Of course, the remote desktop tool here is not necessarily the same.
I have explained the two examples clearly. It is especially fun to use this tool with netcat. In this case, even if the gateway cannot be controlled for port ing, it can penetrate the NAT. Of course, the premise is to run this tool on the host after NAT.
This tool can only run in Linux, and will be transplanted to windows later.
The source code is as follows, with more than 200 lines
/* $ Id: pf. c, v 1.5 2010/01/14 13:29:08 hh Exp $ */
# Include <stdio. h>
# Include <unistd. h>
# Include <string. h>
# Include <stdlib. h>
# Include <sys/socket. h>
# Include <sys/un. h>
# Include <sys/types. h>
# Include <netinet/in. h>
# Include <arpa/inet. h>
# Include <fcntl. h>
# Include <errno. h>
# Include <signal. h>
# Define BUFSIZE 128*1024
# Define CLIENT 1
# Define SERVER 0
# Define fprintf if (debug) fprintf
# Define perror if (debug) perror
Unsigned char * buf = NULL;
Int flag_udp = 0;
Int interval = 2;
Int debug = 0;
Struct sockfd {
Int type;/* 0: server; 1: client */
Int fd;/* socket */
Char * addr;
Char * port;
Int server;/* server socket */
};
Int init_client_sock (struct sockfd * fd)
{
Int tmpsock = socket (AF_INET, SOCK_STREAM, 0 );
If (tmpsock <0 ){
Perror ("socket ");
Exit (errno );
}
Struct sockaddr_in addr = {0 };
Addr. sin_family = AF_INET;
Addr. sin_addr.s_addr = inet_addr (fd-> addr? Fd-> addr: "127.0.0.1 ");
Addr. sin_port = htons (short) atoi (fd-> port ));
While (connect (tmpsock, (struct sockaddr *) & addr, sizeof (addr) <0 ){
Fprintf (stderr, "connect to % s: % s error. sleep % d sec, then try again... /n ", fd-> addr, fd-> port, interval );
Close (tmpsock );
Tmpsock = socket (AF_INET, SOCK_STREAM, 0 );
Sleep (interval );
}
FD-> FD = tmpsock;
Fprintf (stderr, "connected to % s: % s succeed./N", FD-> ADDR, FD-> port );
Return tmpsock;
}
Int init_server_sock (struct sockfd * FD)
{
Int tmpsock = socket (af_inet, sock_stream, 0 );
If (tmpsock <0 ){
Perror ("socket ");
Exit (errno );
}
Struct sockaddr_in ADDR = {0 };
ADDR. sin_family = af_inet;
ADDR. sin_addr.s_addr = htonl (inaddr_any );
ADDR. sin_port = htons (short) atoi (FD-> port ));
If (BIND (tmpsock, (struct sockaddr *) & ADDR, sizeof (ADDR) <0 ){
Perror ("BIND error ");
Exit (errno );
}
If (Listen (tmpsock, 5) <0 ){
Perror ("Listen error ");
Exit (errno );
}
FD-> Server = tmpsock;
Tmpsock = accept (tmpsock, (struct sockaddr *) null, null );
If (tmpsock <0 ){
Perror ("accept ");
Exit (errno );
}
FD-> FD = tmpsock;
Fprintf (stderr, "One Client Connected in Port % S./N", FD-> port );
Return tmpsock;
}
Void initsock (struct sockfd * FD)
{
If (Server = FD-> type)
Init_server_sock (FD );
Else
Init_client_sock (FD );
Return;
}
Void regetsock (struct sockfd * FD)
{
If (Server = FD-> type ){
Fprintf (stderr, "now waiting for connect.../N ");
Int client = accept (FD-> server, (struct sockaddr *) null, null );
If (client <0 ){
Perror ("accept ");
Exit (errno );
}
FD-> FD = client;
Fprintf (stderr, "There is one client connected in Port % S./N", FD-> port );
} Else if (client = FD-> type ){
Init_client_sock (FD );
}
Return;
}
Int main (INT argc, char * argv [])
{
Int I;
If (argc <= 2 ){
Printf ("/n ");
Printf ("port forward v1.0: forward data between two ports./n ");
Printf ("you can use it as:/n ");
Printf ("pf-l xx/n ");
Printf ("pf-l xx-c xx. xx: xx/n ");
Printf ("pf-c xx. xx: xx-c xx. xx: xx/n ");
Printf ("the ip address can be ignored when it will be set to 127.0.0.1/n ");
Printf ("usage: % s-l port-c [ip:] port [-u] [-t sec] [-v]/n", argv [0]);
Printf ("/n ");
Printf ("-u/tuse udp mode. If not specified-u, default mode is tcp. currently this will be ignored./n ");
Printf ("-l/tlisten ports/n ");
Printf ("-c/tip and port that actively connect/n ");
Printf ("-n/tinterval = <seconds>/n ");
Printf ("-v/tverbose information./n ");
Printf ("/n ");
Printf ("welcome to report bugs to <qianlongwydhh@163.com>/n ");
Exit (0 );
}
Struct sockfd [2];
Int nfd = 0;
For (I = 1; I <argc; I ++ ){
Switch (argv [I] [1]) {
Case 'l ':
If (nfd> 1)
Break;
If (argc = ++ I ){
Printf ("-l need a port number./n ");
Exit (1 );
}
If (atoi (argv [I]) = 0 ){
Printf ("% s is not valid port number! /N ", argv [I]);
Exit (errno );
}
Fd [nfd]. type = SERVER;
Fd [nfd]. addr = NULL;
Fd [nfd]. port = argv [I];
Nfd ++;
Break;
Case 'C ':
If (nfd> 1)
Break;
If (argc = ++ I ){
Printf ("-f need a port number./n ");
Exit (1 );
}
Fd [nfd]. type = CLIENT;
Char * ptr = strchr (argv [I], ':');
If (! Ptr ){
If (atoi (argv [I]) = 0 ){
Printf ("% s is not a valid port number! /N ", argv [I]);
Exit (errno );
}
Fd [nfd]. addr = "127.0.0.1 ";
FD [NFD]. Port = argv [I];
} Else {
FD [NFD]. ADDR = (char *) malloc (PTR-argv [I] + 1 );
Strncpy (FD [NFD]. ADDR, argv [I], PTR-argv [I]);
FD [NFD]. ADDR [PTR-argv [I] = 0;
If (inet_addr (FD [NFD]. ADDR) =-1 ){
Printf ("% s is not a valid IP! /N ", FD [NFD]. ADDR );
Exit (errno );
}
FD [NFD]. Port = ++ PTR;
}
PTR = NULL;
NFD ++;
Break;
Case 'N ':
If (argc = ++ I ){
Printf ("-f need a seconds value./n ");
Exit (1 );
}
If (atoi (argv [I]) = 0 ){
Printf ("% s is not a valid number./n", argv [I]);
Exit (errno );
}
Interval = atoi (argv [I]);
Break;
Case 'V ':
Debug = 1;
Break;
Case 'U ':
Flag_udp = 1;
Break;
Default:
Printf ("unkown options: % s/n", argv [I]);
}
}
Int num;
Buf = (unsigned char *) malloc (BUFSIZE );
Signal (SIGCHLD, SIG_IGN );
For (I = 0; I <2; I ++)
Initsock (& fd [I]);
Pid_t pid;
While (1 ){
Pid = fork ();
If (pid = 0 ){
While (num = read (fd [0]. fd, buf, BUFSIZE)> 0 ){
Int TMP = (INT) write (FD [1]. FD, Buf, num );
Fprintf (stderr, "Chile: 0 -- & gt; 1% d Bytes/N", TMP );
}
If (Num <= 0)
Perror ("Child: read error ");
Kill (getppid (), sigkill );
If (client = FD [0]. Type ){
Close (FD [0]. FD );
}
Regetsock (& fd [0]);
} Else {
While (num = read (fd [1]. fd, buf, BUFSIZE)> 0 ){
Int tmp = (int) write (fd [0]. fd, buf, num );
Fprintf (stderr, "parent: 1 -- & gt; 0% d bytes/n", tmp );
}
If (num <= 0)
Perror ("child: read error ");
Kill (pid, SIGKILL );
If (client = FD [1]. Type ){
Close (FD [1]. FD );
}
Regetsock (& FD [1]);
}
}
Return 0;
}