•  

ГлавнаяIndyЧастые вопросы по Indy → Как программу заставить работать через Proxy?

Создано: 24.05.2014 23:20:59 · Исправлено: 24.05.2014 23:20:59 · Прочтений: 1266

Как программу заставить работать через Proxy?
Дело в том, что мне необходимо в моей программе сделать возможным работать не только через прямое соединение, но и через Proxy - сервер, а соответствующего свойства у компонента TSocketConnection нету, в отличие от TWebConnection (странно)! Я так предполагаю есть какой-нибудь компонент говорящий моей программе о Proxy - сервере зарегистрированном в системе (речь идет о Windows XP, у которой в свойствах обозревателя указано: Работать через проксу) либо какая-нибудь API функция, делающая последнее.
Я не знаю, то ли это то что вам нужно. Но можно выставить настройки прокси-сервера в системе с помощью WMI:
function SetProxy(const Server : string=;const port:string=) : integer;
var Retvar : integer;
    oBindObj : IDispatch;
    oProxies,oProxy,oWMIService : OleVariant;
    i,iValue: longword;
    oEnum : IEnumvariant;
    oCtx : IBindCtx;
    oMk : IMoniker;
    sFileObj : widestring;
    q,w:string;
begin
  Retvar := 0;
  sFileObj := winmgmts:\\.\root\cimv2;
  // Connect to WMI - Emulate API GetObject()
  OleCheck(CreateBindCtx(0,oCtx));
  OleCheck(MkParseDisplayNameEx(oCtx,PWideChar(sFileObj),i,oMk));
  OleCheck(oMk.BindToObject(oCtx,nil,IUnknown,oBindObj));
  oWMIService := oBindObj;
  oProxies := oWMIService.ExecQuery(Select * from Win32_Proxy);
  oEnum := IUnknown(oProxies._NewEnum) as IEnumVariant;
  while oEnum.Next(1,oProxy,iValue) = 0 do begin
    try
      q:=oProxy.ProxyPortNumber;
      w:=oProxy.ProxyServer;
      if server =  then
        Retvar := oProxy.SetProxySetting()
      else
        Retvar := oProxy.SetProxySetting(server,port);
    except
      Retvar := -1;
    end;
    oProxy := Unassigned;
  end;
  oProxies := Unassigned;
  oWMIService := Unassigned;
  Result := Retvar;
end;
Для работы через прокси лучше использовать Indy компоненты. Если задача использовать использовать TSocketConnection, то его тоже можно использовать соединившись им с прокси сервером и передав вначала данные того прокси протокола, который хотите использовать вот как соединиться по протоколу SOCKS4,5 (взято из indy)
  const
    { Socks messages }
    RSSocksRequestFailed = Request rejected or failed.;
    RSSocksRequestServerFailed = Request rejected because SOCKS server cannot connect.;
    RSSocksRequestIdentFailed = Request rejected because the client program and identd report different user-ids.;
    RSSocksUnknownError = Unknown socks error.;
    RSSocksServerRespondError = Socks server did not respond.;
    RSSocksAuthMethodError = Invalid socks authentication method.;
    RSSocksAuthError = Authentication error to socks server.;
    RSSocksServerGeneralError = General SOCKS server failure.;
    RSSocksServerPermissionError = Connection not allowed by ruleset.;
    RSSocksServerNetUnreachableError = Network unreachable.;
    RSSocksServerHostUnreachableError = Host unreachable.;
    RSSocksServerConnectionRefusedError = Connection refused.;
    RSSocksServerTTLExpiredError = TTL expired.;
    RSSocksServerCommandError = Command not supported.;
    RSSocksServerAddressError = Address type not supported.;

    function MakeSOCKSv4Connection(): boolean;
    var
      AHost: string;
      APort: integer;
      UserName,Password: string;
      i: Integer;
      LRequest: TIdSocksRequest;
      LResponse: TIdSocksResponse;
    begin
      Result:=false;
      try
      if ((ProxyServerHost = ) OR (ProxyServerPort = 0)) then Exit; //. ->
      ServerSocket.RemoteHost:=ProxyServerHost;
      ServerSocket.RemotePort:=IntToStr(ProxyServerPort);
      ServerSocket.Active:=false;
      ServerSocket.Active:=true;
      AHost:=ServerHost;
      APort:=StrToInt(ServerPort);
      //.
      if (GStack = nil) then GStack:=TIdStack.CreateStack();
      LRequest.Version := 4;
      LRequest.OpCode  := 1;
      LRequest.Port := GStack.WSHToNs(APort);
      LRequest.IpAddr := GStack.StringToTInAddr(GStack.ResolveHost(AHost));
      LRequest.UserName := Username;
      i := Length(LRequest.UserName); // calc the len of username
      LRequest.UserName[i + 1] := #0;
      i := 8 + i + 1; // calc the len of request
      LResponse.OpCode:=93;
      ServerSocket.SendBuf(LRequest, i);
      ServerSocket.ReceiveBuf(LResponse, Sizeof(LResponse));
      case LResponse.OpCode of
        90: ;// request granted, do nothing
        91: Raise Exception.Create(RSSocksRequestFailed); //. =>
        92: Raise Exception.Create(RSSocksRequestServerFailed); //. =>
        93: Raise Exception.Create(RSSocksRequestIdentFailed); //. =>
        else Raise Exception.Create(RSSocksUnknownError); //. =>
      end;
      Result:=true;
      except
        end;
    end;

    function MakeSOCKSv5Connection(const flUserAuthentication: boolean): boolean;
    var
      AHost: string;
      APort: Integer;
      Authentication: TSocksAuthentication;
      UserName,Password: string;

      len, pos, sz: Integer;
      tempBuffer: array [0..255] of Byte;
      ReqestedAuthMethod,
      ServerAuthMethod: Byte;
      tempPort: Word;
    begin
      Result:=false;
      try
      if ((ProxyServerHost = ) OR (ProxyServerPort = 0)) then Exit; //. ->
      ServerSocket.RemoteHost:=ProxyServerHost;
      ServerSocket.RemotePort:=IntToStr(ProxyServerPort);
      ServerSocket.Active:=false;
      ServerSocket.Active:=true;
      AHost:=ServerHost;
      APort:=StrToInt(ServerPort);
      if (flUserAuthentication)
      then begin
        Authentication:=saUsernamePassword;
        UserName:=ProxyServerUserName;
        Password:=ProxyServerUserPassword;
        end
      else Authentication:=saNoAuthentication;
      //.
      if (GStack = nil) then GStack:=TIdStack.CreateStack();
      // defined in rfc 1928
      if Authentication = saNoAuthentication then begin
        tempBuffer[2] := $0  // No authentication
      end else begin
        tempBuffer[2] := $2;  // Username password authentication
      end;
      //.
      ReqestedAuthMethod := tempBuffer[2];
      tempBuffer[0] := $5;    // socks version
      tempBuffer[1] := $1;    // number of possible authentication methods
      //.
      len := 2 + tempBuffer[1];
      ServerSocket.SendBuf(tempBuffer, len);
      try
        sz:=ServerSocket.ReceiveBuf(tempBuffer, 2); // Socks server sends the selected authentication method
        if (sz <> 2) then Raise Exception.Create();
      except
        On E: Exception do begin
          raise EIdSocksServerRespondError.Create(RSSocksServerRespondError);
        end;
      end;
      //.
      ServerAuthMethod := tempBuffer[1];
      if (ServerAuthMethod <> ReqestedAuthMethod) or (ServerAuthMethod = $FF) then begin
        raise EIdSocksAuthMethodError.Create(RSSocksAuthMethodError);
      end;
      // Authentication process
      if Authentication = saUsernamePassword then begin
        tempBuffer[0] := 1; // version of subnegotiation
        tempBuffer[1] := Length(Username);
        pos := 2;
        if Length(Username) > 0 then begin
          Move(Username[1], tempBuffer[pos], Length(Username));
        end;
        pos := pos + Length(Username);
        tempBuffer[pos] := Length(Password);
        pos := pos + 1;
        if Length(Password) > 0 then begin
          Move(Password[1], tempBuffer[pos], Length(Password));
        end;
        pos := pos + Length(Password);

        ServerSocket.SendBuf(tempBuffer, pos); // send the username and password
        try
          sz:=ServerSocket.ReceiveBuf(tempBuffer, 2);    // Socks server sends the authentication status
          if (sz <> 2) then Raise Exception.Create();
        except
          On E: Exception do begin
            raise EIdSocksServerRespondError.Create(RSSocksServerRespondError);
          end;
        end;
        if tempBuffer[1] <> $0 then begin
          raise EIdSocksAuthError.Create(RSSocksAuthError);
        end;
      end;
      // Connection process
      tempBuffer[0] := $5;  // socks version
      tempBuffer[1] := $1;  // connect method
      tempBuffer[2] := $0;  // reserved
      // for now we stick with domain name, must ask Chad how to detect
      // address type
      tempBuffer[3] := $3;  // address type: IP V4 address: X01    {Do not Localize}
                            //              DOMAINNAME:    X03    {Do not Localize}
                            //              IP V6 address: X04    {Do not Localize}
      // host name
      tempBuffer[4] := Length(AHost);
      pos := 5;
      if Length(AHost) > 0 then begin
        Move(AHost[1], tempBuffer[pos], Length(AHost));
      end;
      pos := pos + Length(AHost);
      // port
      tempPort := GStack.WSHToNs(APort);
      Move(tempPort, tempBuffer[pos], SizeOf(tempPort));
      pos := pos + 2;
      ServerSocket.SendBuf(tempBuffer, pos); // send the connection packet
      try
        sz:=ServerSocket.ReceiveBuf(tempBuffer, 5);    // Socks server replies on connect, this is the first part
        if (sz <> 5) then Raise Exception.Create();
      except
        raise EIdSocksServerRespondError.Create(RSSocksServerRespondError);
      end;
      //.
      case tempBuffer[1] of
        0: ;// success, do nothing
        1: raise EIdSocksServerGeneralError.Create(RSSocksServerGeneralError);
        2: raise EIdSocksServerPermissionError.Create(RSSocksServerPermissionError);
        3: raise EIdSocksServerNetUnreachableError.Create(RSSocksServerNetUnreachableError);
        4: raise EIdSocksServerHostUnreachableError.Create(RSSocksServerHostUnreachableError);
        5: raise EIdSocksServerConnectionRefusedError.Create(RSSocksServerConnectionRefusedError);
        6: raise EIdSocksServerTTLExpiredError.Create(RSSocksServerTTLExpiredError);
        7: raise EIdSocksServerCommandError.Create(RSSocksServerCommandError);
        8: raise EIdSocksServerAddressError.Create(RSSocksServerAddressError);
        else
          raise EIdSocksUnknownError.Create(RSSocksUnknownError);
      end;
      // type of destination address is domain name
      case tempBuffer[3] of
        // IP V4
        1: len := 4 + 2; // 4 is for address and 2 is for port length
        // FQDN
        3: len := tempBuffer[4] + 2; // 2 is for port length
        // IP V6
        4: len := 16 + 2; // 16 is for address and 2 is for port length
      end;
      //.
      try
        // Socks server replies on connect, this is the second part
        sz:=ServerSocket.ReceiveBuf(tempBuffer[5], len-1);
        if (sz <> (len-1)) then Raise Exception.Create();
      except
        raise EIdSocksServerRespondError.Create(RSSocksServerRespondError);
      end;
      Result:=true;
      except
        end;
    end;

если нужно взять установки прокси те что использует интернет эксплорер,
то нужно разобрать строку возвращаемую следующей функцией
function GetProxyInfo: string;
var
  ProxyInfo: PInternetProxyInfo;
  Len: DWord;
begin
  Result:= ;
  Len:= 4096;
  GetMem(ProxyInfo, Len);
  try
    if InternetQueryOption(nil, INTERNET_OPTION_PROXY, Pointer(ProxyInfo), Len) then
      if ProxyInfo^.dwAccessType = INTERNET_OPEN_TYPE_PROXY then
      begin
        Result:= ProxyInfo^.lpszProxy
      end;
  finally
    FreeMem(ProxyInfo);
  end;
end;

PS: только в конце заметил, что у меня ServerSocket типа TTcpClient, но он тоже просто читает/пишет сокет, так что TSocketConnection тоже можно будет прикрутить