Transparent proxy technology in Linux

Source: Internet
Author: User
Imagine a scenario where you want to intercept (hijack) a local egress connection (localout) or a forward connection (prerouting), and content in the two directions of the Connection
Make changes, such as: 1. Connect the connection to the remote socks proxy (add socks communication protocol to the communication header) 2. Record the connection (for protocol analysis) 3. Whatever you want
For example, we call it tcpgrep ,:).
So what should we do?
1. Obtain the connection
First of all, we need to get this connection. It is easy to think of using iptables to connect to the Redirect method (similar to DNAT). If you have done squid transparent proxy, you should be familiar with it.

# Iptables-T Nat-A output-p tcp-J redirect -- to-ports 8010

Of course, you should ignore some connections that are not interested. You can create a chain separately and configure it with-J return. If you are familiar with iptables, this should be easy to do.
Not much.

What about now?
NC-l 8010 (Note: if you are using gnu nc, use nc-l-P 8010)

Then NC www.baidu.com 80
Very good. The connection has been hit by the first NC hijack. But the question is, where is he going?

2. Obtain orginal destinaltion
Here is the key to the transparent proxy technology.
0. Socks proxy
This method is not what we need, because it involves modifications to user programs. Because the user needs to send the destination address to the server (according to the SOCKS protocol), if the user program does not consider
There is no direct way to support the SOCKS protocol.

1. Method 1: Build a dedicated kernel module
I used to do one that has related information in http://s5snake.gro.clinux.org and is specifically used for socks [45. However, after Kernel 2.6.9, due to design issues
The connection is invalid. Now I have no longer maintained this old module.
This method is too difficult and difficult to debug. You need to maintain the kernel and user mode modules of Netfilter/iptables at the same time, so it is not recommended to use it again.

2. Method 2: Preload
Preload a database, modify socks, and call the connect function.
That's what tsocks does (http://tsocks.sourceforge.net /)
This method is very similar to the sockscap32 program in windows, but the biggest problem is that it can only be used on the local machine and does not apply to the forwarded connection.

3. Method 3: so_original_dst
So_original_dst is a socket parameter (for the sol_ip Layer ).
The call method is as follows:
Getsockopt (clifd, sol_ip, so_original_dst, & orig_addr, & sin_size );
Clifd is the client socket from hijack, and orig_addr is the sockaddr_in structure parameter, sin_size = sizeof (sockaddr_in ).
Returns 0 if success,-1 fails.
If orig_addr is successful, it will be the direction that the customer really needs to go ...... Lie to me and you will see it later ). Let's give it a piece of code first:
/*
* Simple "Hello, world! "Server
* Patch: demonstrate so_original_dst
*/

# Include <stdio. h> /**/
# Include <stdlib. h>/* exit ()*/
# Include <string. h>/* memset (), memcpy ()*/
# Include <sys/utsname. h>/* uname ()*/
# Include <sys/types. h>
# Include <sys/socket. h>/* socket (), BIND (), listen (), accept (), getsockopt ()*/
# Include <Linux/netfilter_00004.h>
# Include <netinet/in. h>
# Include <ARPA/inet. h>
# Include <netdb. h>
# Include <unistd. h>/* fork (), write (), close ()*/

Char message [bufsiz];
Const int back_log = 5;

Int main (INT argc, char * argv [])
{
Int serversocket = 0,
On = 0,
Port = 0,
Status = 0,
Childpid = 0;
Struct hostent * hostptr = NULL;
Char hostname [80] = "";
Struct sockaddr_in servername = {0 };
Struct sockaddr_in origindst = {0 };
Socklen_t sin_size = sizeof (origindst );

If (2! = Argc)
{
Fprintf (stderr, "Usage: % s portnum/N ",
Argv [0]);
Exit (1 );
}
Port = atoi (argv [1]);
Serversocket = socket (pf_inet, sock_stream,
Ipproto_tcp );
If (-1 = serversocket)
{
Perror ("socket ()");
Exit (1 );
}
On = 1;

Status = setsockopt (serversocket, sol_socket,
So_reuseaddr,
(Const char *) & on, sizeof (on ));

If (-1 = Status)
{
Perror ("setsockopt (..., so_reuseaddr ,...)");
}

{
Struct linger = {0 };

Linger. l_onoff = 1;
Linger. l_linger = 30;
Status = setsockopt (serversocket,
Sol_socket, so_linger,
(Const char *) & linger,
Sizeof (linger ));

If (-1 = Status)
{
Perror ("setsockopt (..., so_linger ,...)");
}
}

/*
* Find out who I am
*/

Status = gethostname (hostname,
Sizeof (hostname ));
If (-1 = Status)
{
Perror ("gethostname ()");
Exit (1 );
}

Hostptr = gethostbyname (hostname );
If (null = hostptr)
{
Perror ("gethostbyname ()");
Exit (1 );
}

(Void) memset (& servername, 0,
Sizeof (servername ));
(Void) memcpy (& servername. sin_addr,
Hostptr-> h_addr,
Hostptr-> h_length );

Servername. sin_addr.s_addr = htonl (inaddr_any );
Servername. sin_family = af_inet;
Servername. sin_port = htons (port );
Status = BIND (serversocket,
(Struct sockaddr *) & servername,
Sizeof (servername ));
If (-1 = Status)
{
Perror ("BIND ()");
Exit (1 );
}
Status = listen (serversocket, back_log );
If (-1 = Status)
{
Perror ("Listen ()");
Exit (1 );
}

For (;;)
{
Struct sockaddr_in clientname = {0 };
Int slavesocket;
Socklen_t clientlength =
Sizeof (clientname );

(Void) memset (& clientname, 0,
Sizeof (clientname ));

Slavesocket = accept (serversocket,
(Struct sockaddr *) & clientname,
& Clientlength );
If (-1 = slavesocket)
{
Perror ("accept ()");
Exit (1 );
}

Childpid = fork ();

Switch (childpid)
{
Case-1:/* Error */
Perror ("fork ()");
Exit (1 );

Case 0:/* child process */

Close (serversocket );

If (-1 = getpeername (slavesocket,
(Struct sockaddr *) & clientname,
& Clientlength ))
{
Perror ("getpeername ()");
}
Else
{
If (getsockopt (slavesocket, sol_ip, so_original_dst, & origindst, & sin_size) = 0 ){
Printf ("New Connection: % s, % u", inet_ntoa (clientname. sin_addr), ntohs (clientname. sin_port ));
Printf ("-> % s, % u/N", inet_ntoa (origindst. sin_addr), ntohs (origindst. sin_port ));
} Else {
Perror ("getsockopt so_original_dst :");
}
}

Do {
Read (slavesocket, message, bufsiz );
Write (1, message, strlen (Message ));
Write (slavesocket, message, strlen (Message ));
} While (Message [0]);
Close (slavesocket );
Exit (0 );

Default:
}
}

Return 0;
}

Before compiling and running, remember
# Iptables-T Nat-A output-p tcp-J redirect -- to-ports [port number]
After running, if everything is normal, then you are very lucky. If you get the server running address and port, then you are unfortunately, you are likely to use the range from 2.6.9 to 2.6.12.
Kernel, obviously this is a bug, see: http://patchwork.netfilter.org/netfilter-devel/patch.pl? Id = 2676
So what should we do?
1. Upgrade the kernel to 2.6.13. 2.6.13 has merged the patch above.
2. downgrade to a lower version of the kernel on the premise that the so_original_dst option is available and the test is normal.
3. Manually analyze the/proc/NET/ip_conntrack file. I personally analyzed the feasibility and thought that this method is a feasible remedy, but I have never started to write _ = _!

Iii. Grace ...... How do you like it?
Use poll or select as the intermediary, perform TCP-grep games (S/microsft/GNU/g, haha), analyze the QQ protocol, and so on. It would be better to write a plug-in framework :)

Related Article

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.