Proxifiers or how it works

Many proxy programs have resorted to the services, but not everyone knows how they work. I will talk about the algorithm laid in their foundation and practical implementation.

Where did it start


A little over five years ago, I lived in a student dormitory and access to the Internet was organized through a proxy server (hereinafter referred to as a proxy). From the point of view of ordinary users, this is not very convenient. Most programs do not know how to work with proxies, and the possibilities of the latter are very limited. But as they say, "we have what we have." Fortunately, there are software products designed to make other programs work with proxies (hereinafter proxifiers). I also used one of these.

At that time, my friend and I were addicted to the game “Sword of the New World”. The game did not make friends with the proxy. Basically, the problem lay in the protection system of the game. Available proxifiers were tried, but to no avail. My friend decided to write his proxy and attracted me to this process. I had ideas about how sockets and proxies work and pretty quickly produced an algorithm "how it should work." A friend, armed with my algorithm and the Delphi development environment, wrote the first proxy implementation, which successfully made friends with the proxy game.

Time has passed. Our development as well as the source code are lost. And how evil the need for a proxy arose (well, companies really like to distribute the Internet through proxies for their employees). Nothing to do, I had to write from scratch. And so the project «azimuth-proxyfier» was born, the device of which will be discussed later. (link to the source at the end of the article)

Everything is very simple


Turning to the documentation for the HTTP / 1.1 protocol, we will find the wonderful CONNECT method introduced to support HTTPS (secure connections to the web server). It works as follows:
  1. a proxy sends a request to connect to a resource (remote socket);
  2. if you are allowed (authorization, ...) the proxy tries to connect to the specified resource;
  3. if everything is ok, a positive answer is sent to you. Then the data goes between you and the remote resource;

Dialog example (request and response end with an empty string, and then raw data):
CONNECT 205.188.11.33:443 HTTP/1.1
Connection: Keep-alive
Host: 205.188.11.33:443
HTTP/1.1 200 Connection established

A proxy acts as a bridge. And this channel is the TCP channel between your socket and the remote socket.
All we need:
  1. write code sending a proxy request and processing a response. And all this should become the handler of the connect function from the socket library.
  2. somehow we need to load our code into the address space of the application (which we want to make friends with a proxy) and make it work.

There are many options for implementing the above points. In my case, the target platform is Windows. In which there is an interesting ability of the system to load dynamic libraries from the directory with the application, and then from the system. As a rule, applications with sockets work through the ws2_32.dll or wsock32.dll library (exists for compatibility with an earlier version of Windows). And for these libraries their “adapters” were written with similar names and a similar set of functions. In fact, the system also has a higher-level library for working with the wininet.dll network and several socket options. But conservatism is a strong thing and most continue to use Berkeley sockets (in Windows it is Winsock 1).

At the time of loading the “adapter”, the latter loads the “real” library and starts broadcasting all function calls, with the exception of two. The first is connect . Our application does not really know anything about the existence of a proxy. It is trying to connect to the direct IP address. And this address passes in the parameters. Here we must do all the work. Our code connects to another address (at the proxy address), where the real connection address is transmitted. “What is the second function?” You ask. If the destination address is entered by the user in the program (and in some other cases), then domain names are used (for example, “www.example.org”). But the connect function does not know how to work with domain names. This is where the gethostbyname function is needed.(with its help, domain names are converted to IP addresses), the processing of which we take over. Here we remember the requested address in the form of a domain name and return the fake address. In the connect function, we do the inverse transformation. When sending a request for a proxy, we can specify the address of both IP and domain name.

For anyone who wants to familiarize themselves with the implementation, read the source code or just use the finished product, welcome to the project page http://code.google.com/p/azimuth-proxyfier/ (the project is implemented in C language, distributed under the BSD license) .

The algorithm is valid for most operating systems, you only need to understand how to implement the code.

Thank you all for your attention.

Also popular now: