📜 ⬆️ ⬇️

Proxifiers or how it works

Many have resorted to the services of proxies, but not everyone knows how they work. I will talk about the algorithm underlying them and practical implementation.

How did it start


A little more than five years ago I lived in a student dormitory and Internet access 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 severely limited. But as they say "we have what we have." Fortunately, there are software products designed to make friends with other programs to work with proxies (hereinafter referred to as proxifiers). I used one of these.

At that time, my friend and I got hooked on the game “Sword of the New World”. The game was not friends with the proxy. Basically the problem lay in the defense of the game. The available proxifiers have been tried, but to no avail. My friend decided to write his proxy and attracted me to this process. About how the sockets and proxies work, I had an idea and rather quickly produced an algorithm “how it should work”. A friend, armed with my algorithm and Delphi development environment, wrote the first implementation of the proxifier, which successfully befriended the game with the proxy.
')
The time has passed. Our development as source codes are lost. And as for evil, there was a need for a proxy (well, firms really like to distribute the Internet through a proxy to their employees). Nothing to do, I had to write from scratch. And so the project “azimuth-proxyfier” was born, about which device the discussion will go on. (link to the source at the end of the article)

Everything is very simple


Referring to the documentation for the HTTP / 1.1 protocol, we find a great method CONNECT, introduced to support HTTPS (secure connections to a web server). It works as follows:
  1. the proxy is sent a request to connect to the resource (remote socket);
  2. if you are allowed (authorization, ...), the proxy tries to connect to the specified resource;
  3. If everything is ok, you are sent a positive response. After that, the data between the channel and the remote resource goes through the channel;

An example of a dialogue (the request and the response end with an empty line, and then the 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 <RAWDATA> 

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

The options for implementing the above points are numerous. 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 library. Typically, applications with sockets work through the library ws2_32.dll or wsock32.dll (exists for compatibility with an earlier version of Windows). Here for these libraries their "adapters" with similar names and a similar set of functions were written. 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 the majority continues to use Berkeley sockets (in Windows this is Winsock 1).

At the time of loading the "adapter", the latter loads the "real" library and begins to broadcast all the function calls, with the exception of two. The first is connect . Our application really knows nothing about the existence of a proxy. It tries to connect to a direct IP address. And this address transmits in the parameters. Here we have to do all the work. Our code makes a connection to a different address (at the proxy address), where the real address of the connection is sent. “What is the second function?” You ask. If the destination address is entered by the user in the program (and in some other cases), 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, the domain names are converted into IP addresses), the processing of which we undertake. 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 transform. By transferring a request to the 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, distributed under the BSD license) .

The algorithm is valid for most operating systems, you need to understand only the method of code injection.

Thank you all for your attention.

Source: https://habr.com/ru/post/176113/


All Articles