Example Socks4 Proxy by Aphex

Post date: Aug 20, 2010 1:28:35 AM

{

Example Socks4 Proxy by Aphex

Here is a perfect example of the small and stable

applications that can be created using my units.

This multithreaded Socks4 proxy server covers the

entire Socks4 protocol and is only 11KB compressed.

}

program Socks4;
{..$APPTYPE CONSOLE}
uses
  Windows,
  Winsock,
  ApplicationUnit,
  SocketUnit,
  ThreadUnit;
type
  TSocks4Header = packed record
    bVn: byte;
    bCd: byte;
    wPort: word;
    dIP: in_addr;
  end;
const
  ServerPort: integer = 6699;
var
  Application: TApplication;
  ServerSocket: TServerSocket;
threadvar
  ClientSocket: TClientSocket;
  Socks4Header: TSocks4Header;
procedure RelayData(Socket1, Socket2: TClientSocket);
var
  Buffer: array [0..32767] of byte;
  BytesReceived: integer;
  Nonblocking: integer;
begin
  //put sockects into nonblocking mode
  ioctlsocket(Socket1.Socket, FIONBIO, Longint(Nonblocking));
  ioctlsocket(Socket2.Socket, FIONBIO, Longint(Nonblocking));
  while ((Socket1.Connected) and (Socket2.Connected)) do
  begin
    //try to receive some data from the first socket
    BytesReceived := Socket1.ReceiveBuffer(Buffer, 32768);
    if BytesReceived > 0 then
    begin
      //loop until we can successfully relay to the second
      while Socket2.SendBuffer(Buffer, BytesReceived) = -1 do Sleep(1);
    end;
    //try to receive some data from the second socket
    BytesReceived := Socket2.ReceiveBuffer(Buffer, 32768);
    if BytesReceived > 0 then
    begin
      //loop until we can successfully relay to the first
      while Socket1.SendBuffer(Buffer, BytesReceived) = -1 do Sleep(1);
    end;
    Sleep(1);
  end;
end;
procedure ProxyConnection(Address: in_addr; Port: word);
var
  ProxyClientSocket: TClientSocket;
begin
  {
    The first type of connection is like a simple port
    redirect. The remote client requests us to make a
    connection on their behalf, we make the connection
    and then begin relaying traffic between the two.
  }
  ProxyClientSocket := TClientSocket.Create;
  ProxyClientSocket.Connect(string(inet_ntoa(Address)), ntohs(Port));
  Socks4Header.bVn := 0;
  if ProxyClientSocket.Connected then
  begin
    Socks4Header.bCd := 90;
  end
  else
  begin
    Socks4Header.bCd := 91;
    ProxyClientSocket.Disconnect;
    ProxyClientSocket.Free;
    Exit;
  end;
  ClientSocket.SendBuffer(Socks4Header, sizeof(Socks4Header));
  RelayData(ClientSocket, ProxyClientSocket);
  ProxyClientSocket.Disconnect;
  ProxyClientSocket.Free;
end;
procedure ProxyBinding(Address: in_addr; Port: word);
var
  ProxyClientSocket: TClientSocket;
  ProxyServerSocket: TServerSocket;
begin
  {
    The second is more complex, it binds a local port
    to the remote client and waits for an incomming
    connection. Once the connection is made traffic
    begins relaying as normally. We can reuse the same
    relay for both types of connections.
  }
  ProxyServerSocket := TServerSocket.Create;
  ProxyServerSocket.Listen(0);
  Socks4Header.bVn := 0;
  Socks4Header.bCd := 90;
  Socks4Header.dIP := TInAddr(inet_addr(pchar(ProxyServerSocket.LocalAddress)));
  Socks4Header.wPort := htons(ProxyServerSocket.LocalPort);
  ClientSocket.SendBuffer(Socks4Header, sizeof(Socks4Header));
  ProxyServerSocket.Idle;
  ProxyClientSocket := ProxyServerSocket.Accept;
  if ProxyClientSocket.Connected then
  begin
    if ProxyClientSocket.RemoteAddress = string(inet_ntoa(Address)) then
    begin
      Socks4Header.bCd := 90;
    end
    else
    begin
      Socks4Header.bCd := 91;
      ProxyClientSocket.Disconnect;
      ProxyClientSocket.Free;
      Exit;
    end;
  end
  else
  begin
    Socks4Header.bCd := 91;
    ProxyClientSocket.Disconnect;
    ProxyClientSocket.Free;
    Exit;
  end;
  Socks4Header.dIP := TInAddr(inet_addr(pchar(ProxyClientSocket.LocalAddress)));
  Socks4Header.wPort := htons(ProxyClientSocket.LocalPort);
  ClientSocket.SendBuffer(Socks4Header, sizeof(Socks4Header));
  RelayData(ClientSocket, ProxyClientSocket);
  ProxyClientSocket.Disconnect;
  ProxyClientSocket.Free;
  ProxyServerSocket.Free;
end;
procedure Client(Thread: TThread);
var
  UserID: string;
begin
  Thread.Lock;
  try
    //accept the new connection
    ClientSocket := ServerSocket.Accept;
  finally
    Thread.Unlock;
  end;
  //receive header
  ClientSocket.ReceiveBuffer(Socks4Header, sizeof(Socks4Header));
  //only handle version 4
  if Socks4Header.bVn = 4 then
  begin
    //receive userid
    UserID := ClientSocket.ReceiveString;
    if Socks4Header.bCd = 1 then
    begin
      //handle connect
      ProxyConnection(Socks4Header.dIP, Socks4Header.wPort);
    end
    else if Socks4Header.bCd = 2 then
    begin
      //handle bind
      ProxyBinding(Socks4Header.dIP, Socks4Header.wPort);
    end;
  end;
  ClientSocket.Disconnect;
  Thread.Free;
end;
procedure Startup;
begin
  ServerSocket := TServerSocket.Create;
  ServerSocket.Listen(ServerPort);
end;
procedure Main;
begin
  //wait for incomming connections
  ServerSocket.Idle;
  //create a new thread for each new connection
  TThread.Create(Client);
end;
procedure Shutdown;
begin
  ServerSocket.Free;
end;
begin
  Application := TApplication.Create;
  Application.Startup := Startup;
  Application.Main := Main;
  Application.Shutdown := Shutdown;
  Application.StayResident;
  Application.Free;
end.

Only Delphi source code is included in the archive.