1

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.
4

1 回答 1

0

如果客户端使用 HTTPCONNECT命令,则代理根本不应该使用 SSL 本身或对其进行操作。它唯一的工作就是在客户端和目标服务器之间建立一个原始套接字连接,然后在它们之间来回传递原始数据,仅此而已。对于 SSL,这非常重要,因为代理必须先建立原始连接,然后客户端直接与目标服务器握手,而不是与代理服务器握手,否则客户端无法验证服务器的证书以保护连接。这是TIdHTTPProxyServer默认情况下的行为方式,因此在这种情况下不要尝试手动激活 SSL!

如果客户端使用的是 HTTP GETPOSTHEAD命令,则客户端不会直接与目标服务器通信。客户端指定代理要连接的完整 URL,然后TIdHTTPProxyServer充当客户端的 HTTP 服务器,并充当其自己的目标服务器的 HTTP 客户端。在这种情况下,客户端必须直接握手TIdHTTPProxyServer。在这种情况下需要注意的一个问题是,由于指定了完整的 URL,因此 URL 中指定的协议隐含了端口号(HTTP 与 HTTPS)。因此,TIdTCPClient(AContext.OutboundClient).Port即使对于 HTTPS URL,机会通常为 80,除非客户端连接到非标准端口,因为TIdHTTPProxyServer当前在连接到目标服务器之前不区分 HTTP 和 HTTPS URL。

您可以使用该TIdHTTPProxyServerContext.Command属性来了解客户端是否正在使用该CONNECT命令。

您将不得不手动处理端口问题,直到TIdHTTProxyServer可以修复。

尝试更多类似的东西:

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;
于 2013-07-16T20:07:01.393 回答