我使用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()
可以检测并包装为引发的异常(EIdOSSLUnderlyingCryptoError
,EIdOSSLAcceptError
,EIdSocketError
等,具体取决于错误代码的性质)在等待握手完成的客户端线程的上下文中。
但是,当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/