Ir al contenido


Foto

Mini Proxy


  • Por favor identifícate para responder
6 respuestas en este tema

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 08 abril 2015 - 01:14

Os presento un mini servidor proxy que desvía nuestro tráfico de internet hacia otro servidor Proxy, que llamaré Proxy real.

 

En un principio tuve necesidad de no conectar directamente con el servidor Proxy real, sino hacerlo a través de otro PC, para ello escribí esta pequeña aplicación que hace de intermediaria entre un explorador y el Proxy real.

 

Su funcionamiento es muy simple, básicamente se trata de un servidor de escucha a nivel socket y al tiempo conecta con el Proxy real en su puerto. Un hilo se encargara de establecer la conexión entre ambos lados y se trasmitir todo el diálogo http.

 

El código no usa componentes, es a nivel de sockets.  Puede funcionar como un pequeño espía o debuger al ver el tráfico. El debuger es muy rudimentario, mostraría todos los mensajes de todos los hilos creados. Cada 64K borra el Memo donde muestra los comandos para no sobrecargarlo.

 

La interfece consta de tres edit:

1.- Puerto de comunicación con nuestro Proxy ( la IP será la máquina donde se ejecute)

2.- Dirección del Proxy real

3.- Puerto del Proxy real

 

El proyecto es un prototipo y puede mejorarse mucho, e incluso convertirlo en un Proxy real interpretando los comandos http.

 

El núcleo del servidor-cliente es el siguiente código, compuesto de dos TThreard, el servidor y los hilos de comunicación por cada cliente conectado.


delphi
  1. unit ThProxy;
  2.  
  3. interface
  4.  
  5. uses
  6. Classes, Windows, Messages, winsock, syncobjs;
  7.  
  8. type
  9. TServer = class(TThread)
  10. private
  11. Sock_e: TSOCKET; // Sock de escucha
  12. FPort: DWORD;
  13. protected
  14. procedure Execute; override;
  15. public
  16. Constructor Create(Port: DWORD; _ProxyServer: String; _ProxyPort: DWORD);
  17. procedure Close();
  18. end;
  19.  
  20. TClient = class(TThread)
  21. private
  22. FDSet: TFDSet;
  23. FSocket: TSOCKET;
  24. DSocket: TSOCKET;
  25. Buffer: PCHAR;
  26. function Connect(IP: PCHAR; Port: DWORD): TSOCKET;
  27. function Select(): integer;
  28. procedure SendLog();
  29. function SendHttp(Socket1, Socket2: TSOCKET): boolean;
  30. function TrasmitHttp: boolean;
  31. protected
  32. procedure Execute; override;
  33. public
  34. Constructor Create(Socket: TSOCKET);
  35. end;
  36.  
  37. implementation
  38.  
  39. { TServer }
  40. uses Unit1;
  41.  
  42. const
  43. BUFSIZE = 124*16;
  44.  
  45. var
  46. CS: TCriticalSection;
  47. ProxyServer: String;
  48. ProxyPort: DWORD;
  49.  
  50. function GetReadableBytes(Sock: TSOCKET): integer;
  51. begin
  52. Result:= -1;
  53. if ioctlsocket(sock, FIONREAD, Result) < 0 then
  54. Result:= 0;
  55. end;
  56.  
  57.  
  58. Constructor TServer.Create(Port: DWORD; _ProxyServer: String; _ProxyPort: DWORD);
  59. begin
  60. inherited Create(false);
  61. FreeOnTerminate:= true;
  62. FPort:= Port;
  63. ProxyServer:= _ProxyServer;
  64. ProxyPort:= _ProxyPort;
  65. end;
  66.  
  67. procedure TServer.Close();
  68. begin
  69. closesocket(Sock_e);
  70. Terminate;
  71. end;
  72.  
  73. procedure TServer.Execute;
  74. var
  75. Wsa: WSADATA;
  76. Sock_c: TSOCKET; // Sock de comunicación
  77. Addr_s, Addr_c: sockaddr_in;
  78. Len: integer;
  79. begin
  80. Len:= 0;
  81.  
  82. // Inicializamos
  83. if WSAStartup(MAKEWORD(2, 0), Wsa) <> 0 then exit;
  84. CS:= TCriticalSection.Create;
  85.  
  86. //Creamos el socket
  87. Sock_e:= socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  88. if Sock_e <> INVALID_SOCKET then
  89. begin
  90. // Dirección IP y puerto
  91. Addr_s.sin_family:= AF_INET;
  92. Addr_s.sin_addr.s_addr:= INADDR_ANY;
  93. Addr_s.sin_port:= htons(FPort);
  94.  
  95. // Asociamos el socket al puerto
  96. if bind(Sock_e, Addr_s, sizeof(sockaddr_in)) <> -1 then
  97. begin
  98. // Escuchando puerto
  99. if listen(Sock_e, 1) <> -1 then
  100. begin
  101. // Bucle principal del servidor
  102. while not Terminated do
  103. begin
  104. //hay una conexión entrante y la aceptamos
  105. Len:= sizeof(sockaddr_in);
  106. Sock_c:= accept(Sock_e, @Addr_c, @Len);
  107. if Sock_c <> INVALID_SOCKET then
  108. TClient.Create(Sock_c);
  109. end;
  110. end;
  111. closesocket(Sock_e);
  112. end; // if(bind)
  113. end; // if(Sock_e)
  114.  
  115. CS.Free;
  116. WSACleanup;
  117. end;
  118.  
  119.  
  120. function TClient.Connect(IP: PCHAR; Port: DWORD): TSOCKET;
  121. var
  122. host: Phostent;
  123. direc: sockaddr_in;
  124. Error: boolean;
  125. begin
  126. Error:= true;
  127. Result:= -1;
  128. Result:= socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  129. if(Result <> -1) then
  130. begin
  131. //Dirección IP del servidor y Puerto
  132. host:= gethostbyname(IP);
  133. if host <> nil then
  134. begin
  135. direc.sin_family:= AF_INET;
  136. direc.sin_port:= htons(Port);
  137. direc.sin_addr.S_addr:= PInAddr(host.h_addr_list^)^.S_addr;
  138. ZeroMemory(@direc.sin_zero[0], 8);
  139. if Winsock.Connect(Result, direc, sizeof(direc)) <> -1 then
  140. Error:= false;
  141. end;
  142. if Error then
  143. begin
  144. closesocket(Result);
  145. Result:= -1;
  146. end;
  147. end;
  148. end;
  149.  
  150.  
  151. Constructor TClient.Create(Socket: TSOCKET);
  152. begin
  153. inherited Create(false);
  154. FreeOnTerminate:= true;
  155. FSocket:= Socket;
  156. end;
  157.  
  158. function TClient.Select(): integer;
  159. var
  160. Time: timeval;
  161. begin
  162. Time.tv_sec:= 0;
  163. Time.tv_usec:= 10;
  164.  
  165. FD_ZERO(FDSet);
  166. FD_SET(FSocket, FDSet);
  167. FD_SET(DSocket, FDSet);
  168.  
  169. // Comprobamos si ha recibido algun mensaje
  170. Result:= Winsock.select(0, @FDSet, 0, 0, @Time);
  171. end;
  172.  
  173. procedure TClient.SendLog();
  174. begin
  175. try
  176. CS.Enter;
  177. with Form1 do
  178. begin
  179. if CheckBox1.Checked then
  180. begin
  181. if Length(Memo1.Text) + lstrlen(Buffer) >= 64000 then Memo1.Clear;
  182. Memo1.Text:= Form1.Memo1.Text + Buffer;
  183. Memo1.Perform( EM_LINESCROLL, 0, Memo1.Lines.Count);
  184. end;
  185. end;
  186. finally
  187. CS.Leave();
  188. end;
  189. end;
  190.  
  191. function TClient.SendHttp(Socket1, Socket2: TSOCKET): boolean;
  192. var
  193. Count, Len, nBytes: DWORD;
  194. begin
  195. Count:= 0;
  196. Len:= 0;
  197. Buffer^:= #0;
  198. nBytes:= GetReadableBytes(Socket1);
  199. if nBytes>0 then
  200. begin
  201. if FSocket = Socket1 then
  202. lstrcpy(Buffer, #13+#10 + 'Local:' + #13+#10)
  203. else
  204. lstrcpy(Buffer, #13+#10 + 'Remoto:' + #13+#10);
  205. SendLog;
  206. end;
  207. while (nBytes > 0) and (Len <> -1) do
  208. begin
  209. if nBytes > BUFSIZE-1 then nBytes:= BUFSIZE-1;
  210. Len:= recv(Socket1, Buffer^, nBytes, 0); //recibimos los datos que envie
  211. if Len > 0 then
  212. begin
  213. Count:= Count + Len;
  214. Buffer[Len]:= #0;
  215. SendLog;
  216. send(Socket2, Buffer^, Len, 0);
  217. end;
  218. nBytes:= GetReadableBytes(Socket1);
  219. end;
  220.  
  221. Result:= Count > 0;
  222. end;
  223.  
  224. function TClient.TrasmitHttp: boolean;
  225. begin
  226. Result:= false;
  227. Buffer^:= #0;
  228. repeat
  229. Select();
  230. // recibo de la fuente y envío al destino
  231. if FD_ISSET(FSocket, FDSet) then
  232. SendHttp(FSocket, DSocket);
  233.  
  234. // Recibo respuesta de destino y la envío a la fuente
  235. if FD_ISSET(DSocket, FDSet) then
  236. Result:= SendHttp(DSocket, FSocket);
  237. until Buffer^ = #0
  238. end;
  239.  
  240. procedure TClient.Execute;
  241. var
  242. Len: integer;
  243. T: boolean;
  244. begin
  245. Len:= 0;
  246. Buffer:= nil;
  247. GetMem(Buffer, BUFSIZE);
  248. T:= false;
  249.  
  250. // Bucle de comunicación
  251. repeat
  252. DSocket:= Connect(PCHAR(ProxyServer), ProxyPort);
  253. if DSocket <> -1 then
  254. T:= TrasmitHttp;
  255. closesocket(DSocket);
  256. until not T;
  257.  
  258. closesocket(FSocket);
  259. FreeMem(Buffer);
  260. end;
  261.  
  262. end.

Para probarlo en nuestro PC podemos configurar el navegador para que el proxy sea 127.0.0.1 en el puerto 8080. En nuestro miniproxy estableceremos los valores del puerto de escucha (8080) y del proxy real.

 

Adjunto el código completo del proyecto.

 

 

 

Saludos.

Archivos adjuntos


  • 3

#2 FGarcia

FGarcia

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 687 mensajes
  • LocationMéxico

Escrito 08 abril 2015 - 02:21

Como siempre, códigos que no entiendo  :cry:  :embarrassed:

 

Sin embargo tus aportaciones son buenísimas.

 

Necesito aprender algo de esto de sockets así que empezare a leer tu código y tratar de entenderlo.

 

Gracias!!


  • 1

#3 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4.945 mensajes
  • LocationMéxico

Escrito 08 abril 2015 - 02:24

Enorme aporte amigo.

 

En la empresa usamos un el proxy squid así que podré hacer algunas pruebas... :D


  • 0

#4 seoane

seoane

    Advanced Member

  • Administrador
  • 1.259 mensajes
  • LocationEspaña

Escrito 08 abril 2015 - 04:32

Muy interesante escafandra.

 

Por lo que puedo ver funciona como un repetidor de TCP. Yo cuando necesito algo asi echo mano del ncat, la navaja suiza de las redes


php
  1. ncat -k -l 8080 -e "ncat proxyreal 8080"


  • 1

#5 seoane

seoane

    Advanced Member

  • Administrador
  • 1.259 mensajes
  • LocationEspaña

Escrito 08 abril 2015 - 04:51

Por cierto, hablando de "repetidores" y proxys, me acabo de acordar de un programa llamado desproxy que hacia algo muy util cuando se esta detras de un proxy, saltarselo :D

 

Basicamente saca provecho del metodo "Connect" que tienen implementado muchos proxys y que sirve para establecer una conexion directa entre el navegador y el servidor para poder utilizar de forma segura el protocolo https. El programa se configura para que escuchara en un puerto, y cuando alguien se conectaba usaba el metodo Connect para saltarse el proxy y reenviar la conexion a un servidor mas alla del proxy.

 

No creo que sea muy complicado hacer un programa similar ... dejo ahi la idea :p

 

PD: Y como soy un aguafiestas, mi solucion con ncat


php
  1. ncat -k -vvv -l 8080 -e "ncat --proxy ipdelproxy:8080 servidordefuera puerto"


  • 0

#6 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 08 abril 2015 - 05:53

Eso es, seoane, es un repetidor TCP. Sobre el tema de ncat, es indiscutible su utilidad pero que le voy a hacer, soy un amante del "hágalo usted mismo", no me puedo contener. 10.gif

 

 

Saludos.


  • 1

#7 sir.dev.a.lot

sir.dev.a.lot

    Advanced Member

  • Miembros
  • PipPipPip
  • 545 mensajes
  • Location127.0.0.1

Escrito 19 julio 2016 - 05:54

Esta interesante el Codigo y el Articulo.... me recuerda los años de Windows 2000, donde hacer aplicaciones de puertos para Puertas Traseras se volvio muy Popular.

 

Saludos!


  • 0




IP.Board spam blocked by CleanTalk.