我使用Delphi 10.1 Update 2和Indy 10.6.2.5341。

我们在SSL_accept中遇到访问冲突。如果使用SSL设置了TIdTCPServer,并且TIdTCPServer已停止,则存在尚未协商TLS的开放连接,就会发生这种情况。

这看起来像Libssl32或Indy中的问题。使用RAW连接,可以使用以下代码和Putty简单地复制此代码。有谁知道防止这些崩溃的解决方案(或解决方法)?

procedure TSslCrash.HandlerOnExecute(AContext: TIdContext);
begin
  //
end;

procedure TSslCrash.HandlerOnConnect(AContext: TIdContext);
begin
  TIdSSLIOHandlerSocketBase(AContext.Connection.IOHandler).PassThrough := False;
end;

procedure TSslCrash.ButtonStartClick(Sender: TObject);
begin
  LServer := TIdTCPServer.Create;
  LIOHandler := TIdServerIOHandlerSSLOpenSSL.Create;

  LIOHandler.SSLOptions.Mode := sslmServer;
  LIOHandler.SSLOptions.Method := sslvTLSv1_2;
  LIOHandler.SSLOptions.VerifyMode := [];
  LIOHandler.SSLOptions.VerifyDepth := 0;
  LIOHandler.SSLOptions.CertFile := 'localhost.crt';
  LIOHandler.SSLOptions.RootCertFile := 'localhost.crt';
  LIOHandler.SSLOptions.KeyFile := 'localhost.key';

  LServer.Bindings.Add.Port := 10000;
  LServer.IOHandler := LIOHandler;
  LServer.OnExecute := HandlerOnExecute;
  LServer.OnConnect := HandlerOnConnect;
  LServer.Active := True;

  //Now open a RAW connection with Putty on port 10000 and keep it open
end;

procedure TSslCrash.ButtonStopClick(Sender: TObject);
begin
  if Assigned(LServer) then begin
    LServer.Active := False;  //This causes an AV in TIdSSLSocket.Accept

    FreeAndNil(LIOHandler);
    FreeAndNil(LServer);
  end;
end;

最佳答案

当以原始模式连接Putty时,不会执行SSL / TLS握手,因此SSL_accept()会停留在等待永不到达的握手请求中。

禁用TIdTCPServer时,它将断开活动的套接字连接,从而使其他线程中正在进行的任何阻塞套接字操作失败。在SSL_accept()的情况下,应将其解除阻止,以使其退出并显示错误代码,然后TIdSSLSocket.Accept()可以检测并包装为引发的异常(EIdOSSLUnderlyingCryptoErrorEIdOSSLAcceptErrorEIdSocketError等,具体取决于错误代码的性质)在等待握手完成的客户端线程的上下文中。

但是,当TIdTCPServer在停用期间断开套接字连接时,将调用TIdTCPConnection.Disconnect(),该调用将调用TIdIOHandler.Close(),该TIdSSLIOhandlerSocketOpenSSL已被覆盖以释放其内部TIdSSLSocket对象-与调用SSL_accept()相同的对象。因此很有可能在停用线程的上下文中在SSL(调用TIdSSLSocket.Destroy()SSL_shutdown())中释放了底层OpenSSL SSL_free()对象,同时仍在TIdSSLObject.Accept()中使用它(仍在调用) SSL_accept())在客户端线程的上下文中,从而导致访问冲突。

在不更改Indy的源代码的情况下,无法做很多事情。例如,可以更改TIdCustomTCPServer.DoTerminateContext()而不是AContext.Binding.CloseSocket()来调用AContext.Connection.Disconnect(False),这样就不会关闭IOHandler本身,而是关闭其下一个套接字(类似于TIdCustomTCPServer.StopListening()终止其侦听accept()线程时的操作)。

我已经在Indy的问题跟踪器中为您打开了一张票:

#218: Access Violation in SSL_accept() when deactivating TIdTCPServer

关于delphi - TIdTCPServer停止时SSL_accept中的Indy/Libssl32访问冲突,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51150235/

10-09 16:56