1
votes

i'm developing proxy server using indy 10.5.8 on delphi xe2 as you know TIdHTTPProxyServer does not support ssl navtively so i add a ssl io handler to it and ssl handshake is ok but after that server return error "Socket Error # 10054 Connection reset by peer." and disconnect the ssl libs are ok and i only changed onbefor command like this :

if (TIdTCPClient(AContext.OutboundClient).Port = 443) then
begin
  if not (AContext.OutboundClient.IOHandler is TIdSSLIOHandlerSocketOpenSSL) then
    begin
      if Assigned(AContext.OutboundClient.IOHandler) then
        AContext.OutboundClient.IOHandler.Free;
      AContext.OutboundClient.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(AContext.OutboundClient);
    end;
  SSLClient := TIdSSLIOHandlerSocketOpenSSL(AContext.OutboundClient.IOHandler);
  SSLClient.SSLOptions.Method     := sslvSSLv23;
  SSLClient.SSLOptions.Mode       := sslmClient;
  SSLClient.SSLOptions.SSLVersions:= [sslvSSLv2, sslvSSLv23, sslvSSLv3, sslvTLSv1];
  SSLClient.SSLOptions.VerifyMode := [];
  SSLClient.OnStatus              := StausChange;
  SSLClient.OnStatusInfo          := StausChangeex;
  SSLClient.PassThrough           := False;
  AContext.OutboundClient.IOHandler.ReadTimeout := 5000;
end else if AContext.OutboundClient.IOHandler is TIdSSLIOHandlerSocketOpenSSL then
begin
  TIdSSLIOHandlerSocketOpenSSL(AContext.OutboundClient.IOHandler).PassThrough := true;
end;

and the trace logs is :

Resolving hostname accounts.google.com.
Connecting to 173.194.70.84.
SSL status: "before/connect initialization"
SSL status: "before/connect initialization"
SSL status: "SSLv2/v3 write client hello A"
SSL status: "SSLv3 read server hello A"
SSL status: "SSLv3 read server certificate A"
SSL status: "SSLv3 read server key exchange A"
SSL status: "SSLv3 read server done A"
SSL status: "SSLv3 write client key exchange A"
SSL status: "SSLv3 write change cipher spec A"
SSL status: "SSLv3 write finished A"
SSL status: "SSLv3 flush data"
SSL status: "SSLv3 read finished A"
SSL status: "SSL negotiation finished successfully"
SSL status: "SSL negotiation finished successfully"
Cipher: name = ECDHE-RSA-AES128-GCM-SHA256; description = ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(128) Mac=AEAD
; bits = 128; version = TLSv1/SSLv3; 
SSL status: "SSL negotiation finished successfully"
Disconnected.
Socket Error # 10054
Connection reset by peer.
1
date time is correct?Arioch 'The

1 Answers

0
votes

If the client is using the HTTP CONNECT command, the proxy is not supposed to use, or act on, SSL itself at all. Its sole job is to establish a raw socket connection between the client and the target server, and then pass raw data back and forth between them, nothing more. For SSL, this is very important, because the proxy must establish the raw connection first and then the client handshakes with the target server directly, not with the proxy server, otherwise the client cannot validate the server's certificate to secure the connection. This is how TIdHTTPProxyServer behaves by default, so DO NOT try to manually activate SSL in this situation!

If the client is using the HTTP GET, POST, or HEAD command instead, the client does not communicate with the target server directly. The client specifies the full URL for the proxy to connect to, then TIdHTTPProxyServer acts as an HTTP server to the client, and acts as its own HTTP client to the target server. In this situation, the client has to handshake with TIdHTTPProxyServer directly. One problem to be aware of in this scenario is that because a full URL is being specified, the port number is implied by the protocol specified in the URL (HTTP vs HTTPS). So chances are that TIdTCPClient(AContext.OutboundClient).Port will usually be 80 even for HTTPS URLs, unless the client is connecting to a non-standard port, because TIdHTTPProxyServer does not currently differentiate between HTTP and HTTPS URLs before connecting to the target server.

You can use the TIdHTTPProxyServerContext.Command property to know whether the client is using the CONNECT command or not.

You will have to handle the Port issue manually until TIdHTTProxyServer can be fixed.

Try something more like this instead:

procedure TForm1.IdHTTPProxyServer1Connect(AContext: TIdContext);
begin
  if AContext.Connection.IOHandler is TIdSSLIOHandlerSocketBase then begin
    TIdSSLIOHandlerSocketBase(AContext.Connection.IOHandler).PassThrough := (AContext.Connection.Socket.Binding.Port <> 443);
  end;
end;

procedure TForm1.IdHTTPProxyServer1HTTPBeforeCommand(AContext: TIdHTTPProxyServerContext);
var
  LURI: TIdURI;
  SSLClient: TIdSSLIOHandlerSocketOpenSSL;
begin
  if TextIsSame(AContext.Command, 'CONNECT') then begin
    Exit; // let TIdHTTPProxyServer do its normal behavior...
  end;

  LURI := TIdURI.Create(AContext.Target);
  try
    if not TextIsSame(LURI.Protocol, 'https') then begin
      Exit; // let TIdHTTPProxyServer do its normal behavior...
    end;

    // Port 80 is TIdHTTPProxyServer's default Port when
    // the requested URL does not explicitly specify a
    // port, so update the correct port if needed...
    if (TIdTCPClient(AContext.OutboundClient).Port = 80) and (LURI.Port = '') then begin
      TIdTCPClient(AContext.OutboundClient).Port := 443;
    end;
  finally
    LURI.Free;
  end;

  // The AContext.OutboundClient does not have a default
  // IOHandler assigned yet at this stage...
  SSLClient := TIdSSLIOHandlerSocketOpenSSL.Create(AContext.OutboundClient);
  SSLClient.SSLOptions.Mode       := sslmClient;
  SSLClient.SSLOptions.SSLVersions:= [sslvSSLv2, sslvSSLv3, sslvTLSv1];
  SSLClient.SSLOptions.VerifyMode := [];
  SSLClient.OnStatus              := StausChange;
  SSLClient.OnStatusInfo          := StausChangeex;
  SSLClient.PassThrough           := False;
  SSLClient.ReadTimeout           := 5000;

  AContext.OutboundClient.IOHandler := SSLClient; 
end;