Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.02.11;
Скачать: CL | DM;

Вниз

Перенаправление пакетов (аля proxy)   Найти похожие ветки 

 
Griha   (2006-09-04 19:21) [0]

Есть сетевое приложение, которое работает с "127.0.0.1". Необходимо написать локальный "proxy", который будет перенаправлять все пакеты на другой сервер. Т.е. proxy получает пакет от клиента - не изменяя перенаправляет его удаленному серверу. Proxy получает пакет от удаленного сервера - не изменяя перенаправляет его клиенту. Плюс нужна возможность отправлять свои пакеты на удаленный сервер. Использую TClientSocket и TServerSocket. Как правильно реализовать поставленную задачу?


 
Griha   (2006-09-04 19:27) [1]

Делал так (SS - TSocketServer, CS - TClientServer):
У SS в ClientConnect пишу:
cs.Active:=true;

В ClientRead:
tmp:=Socket.ReceiveText;
cs.Socket.SendText(tmp);

-----
У CS в Read:
tmp:=Socket.ReceiveText;
ss.Socket.Connections[0].SendText(tmp);


Но если клиент соединяется и сразу шлет пакет (ClientRead), то CS еще не активен и не может отправить пакет удаленному серверу. Получается надо сохранять в пакеты в буффер...
Может надо использовать сокеты в блокирующем режиме? Или вообще таким способом лучше не делать?
Посоветуйте решение...


 
Dmitrij_K   (2006-09-04 19:37) [2]

В инете есть исходники Socks прокси на delphi winsock api


 
Dmitrij_K   (2006-09-04 19:40) [3]

Вот он, только надо его отлаживать, ошибки были
program dproxy;

uses
 windows,
 WinSock;

type TSOCKS4_REQUEST=record
      ucVersion : byte;
      ucCommand : byte;
      wDestPort : word;
      dwDestIp  : dword;
    end;

var
 wsaData : TWSADATA;
 sport   : string;
 iport   : word;
 l_sock  : TSocket;
 sock4   : SOCKADDR_IN;
 Client  : TSockAddr;
 Size    : integer;
 h1      : THandle;

procedure FlushRecvBufferUntil(s:TSOCKET;condition:Char);
var
 iReceiveRes : integer;
 cDummy      : char;
begin
 repeat
   iReceiveRes := recv(s, cDummy, sizeof(cDummy), 0);
 until NOT ((iReceiveRes<>SOCKET_ERROR) and (iReceiveRes<>0) and (cDummy<>condition));
end;

procedure SocksHandlerTreadProc(pParam:pointer); stdcall;
var
 s              : TSocket;
 tunnelSock     : TSocket;
 iConnectResult : integer;
 iReceiveRes    : integer;
 iSocketsSet    : integer;
 socks4Request  : TSOCKS4_REQUEST;
 socks4Response : TSOCKS4_REQUEST;
 remoteAddr     : SOCKADDR_IN;
 fds_read       : TFDset;//fd_set;
 tv             : TTimeval;
 cSocksVersion  : byte;
 iSelectResult  : integer;
 loop           : integer;
 ulVal          : u_long;
 swapBuffer     : array[0..4096*16-1] of char;
 iRecvResult    : integer;
begin
 s              := TSOCKET(pParam);
 tunnelSock     := 0;
 loop           := 0;
 while loop=0 do
 begin
   inc(loop);
   iConnectResult := 0;
   iReceiveRes    := 0;
   iSocketsSet    := 0;
   FD_ZERO(fds_read);
   FD_SET(s, fds_read);
   tv.tv_sec     := 30;
   cSocksVersion := 0;
   iSelectResult := select(0, @fds_read, nil, nil, @tv);
   if (iSelectResult=SOCKET_ERROR) or (not iSelectResult>0) then break;
   ulVal := 0;
   ioctlsocket(s, FIONBIO , ulVal);
   iReceiveRes := recv(s, cSocksVersion, 1, MSG_PEEK);
   if cSocksVersion=4 then // 3333333333333333333
   begin
     iReceiveRes := recv(s, socks4Request, sizeof(socks4Request), 0);
     if iReceiveRes=SOCKET_ERROR then break;
     ulVal := 1;
     ioctlsocket(s, FIONBIO , ulVal);
     FlushRecvBufferUntil(s, #0);
     if socks4Request.ucCommand = 1 then
     begin // 2222222222222222222
ulVal := 0;
ioctlsocket(s, FIONBIO, ulVal);
remoteAddr.sin_family := AF_INET;
move(socks4Request.dwDestIp,remoteAddr.sin_addr,sizeof(remoteAddr.sin_addr));
remoteAddr.sin_port := socks4Request.wDestPort;
tunnelSock := socket(AF_INET, SOCK_STREAM, 0);
iConnectResult := connect(tunnelSock, remoteAddr, sizeof(remoteAddr));
if (iConnectResult<>SOCKET_ERROR) then
begin // 1111111111
  socks4Response.ucCommand := 90;
  socks4Response.ucVersion := 0;
  send(s, socks4Response, sizeof(socks4Response), 0);
end else break; // 1111111111
     end else break;// 2222222222222222222
   end else break;// 3333333333333333333
   ulVal := 0;
   ioctlsocket(tunnelSock, FIONBIO, ulVal);
   ioctlsocket(s, FIONBIO, ulVal);
   fillchar(swapBuffer,sizeof(swapBuffer),0);
   tv.tv_sec := 2;
   while true do // 4444444444444444
   begin
     FD_ZERO(fds_read);
     FD_SET(s, fds_read);
     FD_SET(tunnelSock, fds_read);
     iSocketsSet := select(0, @fds_read, nil, nil, @tv); //if (iSocketsSet == SOCKET_ERROR) _leave;
     if iSocketsSet > 0 then // 5555555555555555
     begin
if FD_ISSET(s, fds_read) then
begin
  iRecvResult := recv(s, swapBuffer, sizeof(swapBuffer), MSG_PEEK);
  if (iRecvResult=0)
    then break
    else iRecvResult := recv(s, swapBuffer, sizeof(swapBuffer), 0);
  if (iRecvResult <> SOCKET_ERROR) and (iRecvResult > 0)
    then send(tunnelSock, swapBuffer, iRecvResult, 0)
    else BREAK;
end;

if (FD_ISSET(tunnelSock, fds_read)) then
begin
  iRecvResult := recv(tunnelSock, swapBuffer, sizeof(swapBuffer), MSG_PEEK);
  if iRecvResult = 0
    then break
    else iRecvResult := recv(tunnelSock, swapBuffer, sizeof(swapBuffer), 0);
  if (iRecvResult <> SOCKET_ERROR) and (iRecvResult > 0)
    then send(s, swapBuffer, iRecvResult, 0)
    else break;
end;
     end;  // 5555555555555555
   end; // 4444444444444444
 end; // while loop=0 do
 closesocket(s);
 closesocket(tunnelSock);
end;

begin
 WSAStartup(MAKEWORD(2,0), wsaData);
 l_sock                := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 sock4.sin_family      := AF_INET;
 sock4.sin_port        := htons(1080);
 sock4.sin_addr.s_addr := INADDR_ANY;
 Size                  := SizeOf(Client);
 if (Bind(l_sock,sock4,SizeOf(sock4))=0) and (Listen(l_sock,$FF)=0) then
   while true do CreateThread(nil,0,@SocksHandlerTreadProc,Pointer(accept(l_sock, @Client, @Size)),0,h1);
end.


 
Eraser ©   (2006-09-04 20:35) [4]

> [0] Griha   (04.09.06 19:21)

нужно перенапрявлять пакеты с какого-то определенного порта? если так, то нужно реализовать обычный port mapping.


 
Сергей М. ©   (2006-09-06 16:46) [5]


> Получается надо сохранять в пакеты в буффер


Получается)
Проблем-то нет)


> Может надо использовать сокеты в блокирующем режиме?


Может и надо.
Решать-то тебе .. как разработчику ...


 
Griha   (2006-09-07 11:20) [6]

2Eraser
С конкретного порта, но не просто перенаправлять, но еще и редактировать "на лету", иногда отправлять свои пакеты как серверу, так и клиенту.

2Сергей М.

> Решать-то тебе .. как разработчику ...

Так как я еще далеко не опытный разработчик, а только учусь, то хотел бы услышать совет мастеров.
Проблема в том, что каждый пакет кодируется XOR"ом по ключу. А ключ меняется в зависимости от содержимого пакета. Сейчас использую асинхронные сокеты и ключ частенько сбивается. Проблема может заключаться как раз в этих асинхронных сокетах? Или ошибку надо искать в другом месте?
... и еще часто возникает ошибка "Asynchronous socket error 10053"


 
Сергей М. ©   (2006-09-07 11:28) [7]


> Проблема может заключаться как раз в этих асинхронных сокетах?


Проблема не в них, проблема в твоем непонимании особенностей работы с гнездами в асинхронном неблок.режиме. И кодировка здесь совершенно ни при чем.


 
Griha   (2006-09-07 11:37) [8]

Но почему-то она всё-таки сбивается. К примеру поступает один пакет, начинается его разбор, а в это время приходит еще один пакет, пока первый не разобран и ключ еще не изменен. Начинается разбор второго пакета и ключ уже повреждается. Ведь так?


 
Сергей М. ©   (2006-09-07 11:46) [9]


> первый не разобран


> приходит еще один пакет


> Начинается разбор второго пакета


А зачем ты начинаешь разбор 2-го пакета, не закончив обработку 1-го ?


 
Griha   (2006-09-07 11:51) [10]

Вызов функции разбора пакета происходит в TClientSocket.Read... Как поступить? Использовать блокирующие сокеты? Или помещать все пакеты в буффер? Или есть другой более правильный вариант?


 
Сергей М. ©   (2006-09-07 12:22) [11]


> Вызов функции разбора пакета происходит в TClientSocket.
> Read


Ну так и разбирай там этот пакет спокойно !
А следующий за ним пакет никуда не денется - вновь возникнет событие OnRead, в котором будешь его разбирать.


> помещать все пакеты в буффер?


Да, буферизация требуется.

Ведь OnRead не есть факт доставки целостного пакета (TCP - поточно-ориентированный протокол), это лишь факт того что принимаемый поток данных не пуст и можно попытаться прочитать из него фрагмент данных требуемого размера (<=ReceiveLength).


 
Griha   (2006-09-07 12:26) [12]


> Ну так и разбирай там этот пакет спокойно !
> А следующий за ним пакет никуда не денется - вновь возникнет
> событие OnRead, в котором будешь его разбирать.

А разве событие OnRead не может произойти вложено? Т.е. в момент обработки одного OnRead сработать еще один OnRead?
---
Сейчас искал какую-нибудь хорошую статью на русском про асинхронные сокеты, но ничего не нашел - везде одно и тоже общими фразами.


 
Сергей М. ©   (2006-09-07 12:31) [13]


> А разве событие OnRead не может произойти вложено? Т.е.
> в момент обработки одного OnRead сработать еще один OnRead?
>


Нет, не может.


 
Eraser ©   (2006-09-07 18:47) [14]

> [8] Griha   (07.09.06 11:37)
> Но почему-то она всё-таки сбивается. К примеру поступает
> один пакет, начинается его разбор, а в это время приходит
> еще один пакет, пока первый не разобран и ключ еще не изменен.
> Начинается разбор второго пакета и ключ уже повреждается.
> Ведь так?

вообще меня настраживает идея шифровать каждый пакет транспортного уровня отдельно, если уж на то пошло - лучше создать свои пакеты на прикладном уровне и работать уже с ними.


 
Новичоккк   (2006-09-07 22:13) [15]

Всем спасибо, программа стало работать стабильно

2Eraser
Так и есть. Первые два байта прикладного пакета - его длина. Один пакет транспортного уровня, может содержать несколько прикладных пакетов, а может только часть одного. Ключ меняется при последовательном разборе каждого пакета.



Страницы: 1 вся ветка

Текущий архив: 2007.02.11;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.051 c
15-1169228956
vrem
2007-01-19 20:49
2007.02.11
Есть ли у Вас проблемы с головой?


1-1166603258
fishka
2006-12-20 11:27
2007.02.11
IdTelnet и получение ответов


15-1169056177
Ламот
2007-01-17 20:49
2007.02.11
Перевод 1С с *.dbf на SQL


15-1169438560
Slider007
2007-01-22 07:02
2007.02.11
С днем рождения ! 22 января


15-1169373734
Expell
2007-01-21 13:02
2007.02.11
В чем причина?