Прокси туннелирование. Часть 2

Прокси серверы представляют из себя компьютеры с установленным специализированным программным обеспечением и являются, по сути, обработчиками разнообразных запросов со стороны клиента и передачи их дальше по сети. Они играют большую роль в функционировании компьютерных сетей, как локальных, так и глобальной сети Интернет.

Различают следующие виды прокси серверов:
— шлюз(proxy-gate), основное назначение такого сервера, это подключение локальных сетей к Интернету используя один IP адрес;
— анонимный прокси(анонимайзер), служит для скрытия реального IP адрес компьютера, что дает возможность анонимной работы в сети;
— файрволы(firewall), защита локальных сетей от посягательств из вне;
— кэширующий, содержит копии часто запрашиваемых ресурсов сети и выдает их по запросу клиенту, тем самым ускоряет загрузку данных и снижает загруженность канала.

В основном прокси серверы используются для скрытия собственного IP адреса клиента и замене его на свой, это происходит благодаря тому что, а прокси сервер изменяет заголовок приходящего пакета. Рассмотрим алгоритм работы связки host-proxy-target, где прокси работает по HTTP протоколу, например локальный хост хочет получить html страницу с хоста www.target.ru, для этого:
1. клиент устанавливает соединение с прокси сервером.
2. клиент посылает команду:
CONNECT www.target.ru:port_target HTTP/1.0
User-Agent: TestApp
3. Прокси сервер возвращает код состояния, либо запрос авторизации, либо код успешной обработки команды или ошибку.
4. Если нужна авторизация то команда примет следующий вид:
CONNECT www.target.ru:port_target HTTP/1.0
User-agent: TestApp
Proxy-authorization: basic password
5. Если ошибок не было и соединение установлено успешно, то клиент посылает запрос:
GET /index.htm HTTP/1.0
Host: www.target.ru
6. Прокси сервер создает сокет и устанавливает соединение с www.target.ru и посылает запрос от клиента.
7. Прокси сервер получает ответ от www.target.ru и пересылает его клиенту.

Для более лучшего понимания алгоритма работы с прокси сервером, рассмотрим исходный текст программы, созданной в среде VC++ 6.0, тип приложения “Win32 Console Application”:

//тип прокси сервера HTTP
#include <iostream.h>
#include <conio.h>
#include <stdio.h>
#include <windows.h>
//Подключение Winsock
#pragma comment(lib, "ws2_32.lib")
 
int main()
{
        WSADATA wsaData;
         //стартуем Winsock
        if(!WSAStartup(0x0202,&wsaData))
        {
                cout<<"WSAStartup is ok"<<endl;
                //создаем сокет через который будем
                //работать с прокси сервером
                SOCKET s_kproxy = socket(AF_INET,SOCK_STREAM,0);
                if(s_kproxy != SOCKET_ERROR)
                {
                        sockaddr_in proxy;
                        proxy.sin_family      = AF_INET;
                        //указываем порт прокси сервера
                        proxy.sin_port        = htons(8080);
                        //IP адрес прокси сервера
                        proxy.sin_addr.s_addr = inet_addr("*.*.*.*");
                        //конектимся к серверу
                        if(connect(s_kproxy,(PSOCKADDR)&proxy,sizeof(proxy)) != SOCKET_ERROR)
                        {
                                char szBuffer[10240];
                                sprintf(szBuffer,
                                "CONNECT %s:%d HTTP/1.0\r\nUser-Agent: TestApp\r\n\r\n",
                                "www.target.ru",80);
                                //посылаем команду CONNECT
                                if(send(s_kproxy,szBuffer,strlen(szBuffer),0))
                                {
                                        cout<<"Send - status ok"<<endl;
                                        memset(szBuffer,0,sizeof(szBuffer));
                                        //ждем ответа от прокси сервера
                                        if(recv(s_kproxy,szBuffer,10240,0))
                                        {
                                                cout<<"Buffer: "<<szBuffer<<endl;
                                                //В данном примере нету обработки
                                                //ответа от прокси сервера, предполагается
                                                //что авторизация не нужна и соединение установлено
                                                //успешно...
                                                ZeroMemory(szBuffer,sizeof(szBuffer));
                                                //формируем запрос
                                                lstrcpy(szBuffer,"GET /index.htm HTTP/1.0\r\n");
                                                lstrcat(szBuffer,"Host: www.target.ru\r\n");
                                                lstrcat(szBuffer,"User-Agent: TestApp\r\n\r\n");
                                                //посылаем запрос получения страницы    
                                                if(send(s_kproxy,szBuffer,strlen(szBuffer),0))
                                                {
                                                        cout<<"Send GET - status ok"<<endl;
                                                        ZeroMemory(szBuffer,sizeof(szBuffer));
                                                        //ждем саму страницу
                                                        if(recv(s_kproxy,szBuffer,10240,0))
                                                        {
                                                                cout<<"HTML: "<<endl<<szBuffer<<endl;
 
                                                        }else{cout<<"ERROR: recv 2"<<endl;}
                                                }else{cout<<"ERROR: send GET"<<endl;}
                                        }else{cout<<"ERROR: recv"<<endl;}
                                }else{cout<<"ERROR: send"<<endl;}
                        }else{cout<<"ERROR: connect"<<endl;}
                        //закрываем сокет
                        closesocket(s_kproxy);
                }else{cout<<"ERROR: socket"<<endl;}
                //прекращаем работу Winsock
                if(!WSACleanup())
                {cout<<"WSACleanup is ok"<<endl;}
                else{cout<<"ERROR: WSACleanup"<<endl;}
        }else{cout<<"ERROR: WSAStartup"<<endl;}
 
        cout<<"Press any key to exit"<<endl;
        while(!getch());
        return 0;
}

Также можно создать цепочку из нескольких прокси серверов, для того чтобы максимально скрыть ваш реальный IP адрес. Изменим выше приведенный пример для работы цепочки host-proxy-proxy-target:

connect(…);
char szBuffer[10240];
//формируем команду к прокси №1, для соединения с прокси №2
sprintf(szBuffer,       "CONNECT %s:%d HTTP/1.0\r\nUser-Agent: TestApp\r\n\r\n","192.168.0.155",8080);
                                
if(send(s_kproxy,szBuffer,strlen(szBuffer),0))
{
        cout<<"Send - status ok"<<endl;
        memset(szBuffer,0,sizeof(szBuffer));
        //ждем ответа от прокси №1
        if(recv(s_kproxy,szBuffer,10240,0))
        {
                cout<<"Buffer: "<<szBuffer<<endl;
                memset(szBuffer,0,sizeof(szBuffer));
                //формируем команду к прокси №2 для соединения с целью
                sprintf(szBuffer,
                                        "CONNECT %s:%d HTTP/1.0\r\nUser-Agent: TestApp\r\n\r\n",
                            "www.code.hut1.ru",80);
                if(send(s_kproxy,szBuffer,strlen(szBuffer),0))
                {
                        cout<<"Send - status ok"<<endl;
                        memset(szBuffer,0,sizeof(szBuffer));
                        if(recv(s_kproxy,szBuffer,10240,0))
                        {
                                cout<<"Buffer: "<<szBuffer<<endl;
                                ZeroMemory(szBuffer,sizeof(szBuffer));
                                //запрос
                                lstrcpy(szBuffer,"GET /test.htm HTTP/1.0\r\n");
                                lstrcat(szBuffer,"Host: www.code.hut1.ru\r\n");
                                lstrcat(szBuffer,"User-Agent: TestApp\r\n\r\n");
                                if(send(s_kproxy,szBuffer,strlen(szBuffer),0))
                                {
                                        cout<<"Send GET - status ok"<<endl;
                                        ZeroMemory(szBuffer,sizeof(szBuffer));
                                        if(recv(s_kproxy,szBuffer,10240,0))
                                        {cout<<"HTML: "<<endl<<szBuffer<<endl;}
                                        else{cout<<"ERROR: recv 2"<<endl;}
                                                                
                                }else{cout<<"ERROR: send GET"<<endl;}
                             }else{cout<<"ERROR: recv CONNECT"<<endl;}
                      }else{cout<<"ERROR: send CONNECT"<<endl;}
                }else{cout<<"ERROR: recv"<<endl;}
}else{cout<<"ERROR: send"<<endl;}
closesocket(…);

На этом пока все, надеюсь, вам пригодится выше изложенное.