【问题标题】:Call SSL_shutdown() hang, client still in FIN_WAIT2 status调用 SSL_shutdown() 挂起,客户端仍处于 FIN_WAIT2 状态
【发布时间】:2014-07-31 03:35:17
【问题描述】:

在我的 ActiveUpdate 模块中(从服务器下载文件),如果服务器丢弃 FIN 包,关闭 OpenSSL 连接将挂起(等待超过 2 小时)。

SSL连接关闭伪代码

def  ssl_close():
if (!SSL_shutdown(m_ssl)):
    …
    shutdown(SSL_get_fd(m_ssl), SHUT_WR);
    SSL_shutdown(m_ssl)
    ...

挂起连接的netstat输出

tcp        0      0 192.168.133.135:52453   10.203.136.169:4122     FIN_WAIT2   off (0.00/0/0)

https://www.openssl.org/docs/ssl/SSL_shutdown.html

为了完成双向关闭握手,必须再次调用 SSL_shutdown()。 如果底层 BIO 阻塞,SSL_shutdown() 只会在握手步骤完成或发生错误后返回。

如果调用一次SSL_shutdown()就不会死机,对内存和连接资源有影响吗?

是否有超时机制来控制 OpenSSL 中的 SSL_shutdown() 或更好的方法?

【问题讨论】:

    标签: ssl


    【解决方案1】:

    第一个 SSL_shutdown 将导致向对等方发送关闭警报,以向对等方发出没有更多 SSL 数据到来的信号 - 类似于发送 FIN 或在普通套接字上执行关闭 SHUT_WR。第二个 SSL_shutdown 将一直等到它收到来自对等方的关闭警报。

    为了确保套接字完全处于活动状态,以便对等方发送 SSL 关闭警报并且您会收到它,我建议仅在第二个 SSL_shutdown 完成后关闭底层套接字。 IE。首先将套接字从 SSL 完全降级为普通套接字,然后关闭普通套接字。

    【讨论】:

      【解决方案2】:

      ...如果服务器丢弃了 FIN 包。

      我不认为您看到的问题是由于丢失了FIN。我怀疑(作为 Steffen)您正在等待来自客户端的 close_notify,但客户端没有发送它。


      如果 (!SSL_shutdown(m_ssl)) ...

      SSL_shutdown 返回 -1、0 和 1;不是 0 和 1。


      如果调用一次SSL_shutdown()不会挂掉,对内存和连接资源有影响吗?

      我不这么认为,但在 Valgrind 或其他泄漏检测器工具下验证它可能会更好。


      是否有超时机制来控制 OpenSSL 中的 SSL_shutdown() 或更好的方法?

      我不相信有超时。

      您可以使用两种策略:

      1. 您提出请求,并不关心客户的close_notify
      2. 您希望严格遵守协议,并希望客户也这样做

      调用SSL_shutdown 一次是策略 1。只需关闭套接字并完成它。

      调用SSL_shutdown 两次是策略2。问题是,并非所有客户端都发送它。很多时候,他们会在阅读完所有请求后关闭套接字。

      您可以通过捕获SIGPIPE 来检测第二种情况。如果连接上有SIGPIPE,则客户端关闭了套接字。只需拨打SSL_shutdown 一次。

      Eric Rescorla 在An Introduction to OpenSSL Programming (Part I) 上更详细地介绍了它。这是他提供的服务器端代码:

      51     r=SSL_shutdown(ssl);
      52     if(!r){
      53         /* If we called SSL_shutdown() first then
      54            we always get return value of ’0’. In
      55            this case, try again, but first send a
      56            TCP FIN to trigger the other side’s
      57            close_notify */
      58         shutdown(s,1);
      59         r=SSL_shutdown(ssl);
      60     }
      61
      62     switch(r){
      63     case 1:
      64         break; /* Success */
      65     case 0:
      66     case -1:
      67     default:
      68         berr_exit("Shutdown failed");
      69     }
      

      【讨论】:

      • 谢谢,这解决了我的问题。我处于一个奇怪的境地。我在做SSL_shutdown(),然后是socket->shutdown(), close()。如果我在 Eclipse 中运行这样的二进制文件,那么一切正常。如果从 Ubuntu 命令行运行完全相同的二进制文件,那么它就不能正常工作!!!看到你的回答,我把顺序颠倒了。即socket->shutdown(), close(),然后是SSL_shutdown(),它起作用了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-22
      • 1970-01-01
      相关资源
      最近更新 更多