代码之家  ›  专栏  ›  技术社区  ›  fedj

带阻塞套接字的SSL\u接受

  •  1
  • fedj  · 技术社区  · 16 年前

    我用SSL和 舞台调度 插座。

    我怎样才能解决这个可怕的问题?

    4 回复  |  直到 16 年前
        1
  •  2
  •   Void - Othman    16 年前

    为什么不在调用前将套接字流设置为非阻塞模式 SSL_accept() ,然后阻塞类似的内容 select() 如果SSL\u accept()返回SSL\u ERROR\u WANT\u READ或SSL\u ERROR\u WANT\u WRITE,则返回超时?或者,您可以在调用SSL_accept()之前阻止select()。两者都应该有效。这样,您至少可以限制连接因错误而被阻止的时间 DoS 比如行为/攻击。

    请记住,SSL/TLS是面向记录的,这意味着您必须循环直到读取完整记录。 SSL_pending() 在这种情况下,我们可以提供帮助。

        2
  •  0
  •   Snazzer    16 年前

    您可以将套接字置于非阻塞模式,然后从SSL\u accept中获取案例SSL\u ERROR\u WANT\u READ或SSL\u ERROR\u WANT\u WRITE。然后你可以睡一会儿,然后再次尝试接受SSL。在某个超时值之后,可以退出并关闭ssl和套接字句柄。

    请注意,这将影响所有SSL操作,这意味着您需要为所有读/写/关机调用执行类似的循环。基本上,任何可以返回WANT_READ或WANT_WRITE的调用。

    如果您不喜欢轮询的想法,可以使用select来确定套接字上是否有可用数据……但这可能会变得有点复杂。

        3
  •  0
  •   jano    10 年前

    我认为下面的代码可能会帮助其他人解决这个问题。它没有经过充分的测试,只是作为灵感。

      //Nonblocking SSL accept based on ACE/ace/SSL/SSL_SOCK_Acceptor.cpp
      SSL_CTX* ctx;
      ctx = initServerCTX(); // initialize SSL
      loadCertificates(ctx, certificate, privateKey); // load certs
    
      ...
    
      SSL* ssl = SSL_new(ctx); /* get new SSL state with context */
      SSL_set_fd(ssl, fd); /* set connection socket to SSL state */
    
      int flags = fcntl(fd, F_GETFL, 0);
      if (flags < 0)
      {
        printf("fcntl: F_GETFL \n");
        return false;
      }
      if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
      {
        printf("fcntl: F_SETFL \n");
        return false;
      }
    
      int status = -1;
      struct timeval tv, tvRestore;
      tv.tv_sec = 2;
      tv.tv_usec = 0;
      tvRestore = tv;
    
      fd_set writeFdSet;
      fd_set readFdSet;
    
      do
      {
        tv = tvRestore;
        FD_ZERO(&writeFdSet);
        FD_ZERO(&readFdSet);
    
        status = ::SSL_accept(ssl);
        switch (::SSL_get_error(ssl, status))
        {
        case SSL_ERROR_NONE:
          status = 0; // To tell caller about success
          break; // Done
    
        case SSL_ERROR_WANT_WRITE:
          FD_SET(fd, &writeFdSet);
          status = 1; // Wait for more activity
          break;
    
        case SSL_ERROR_WANT_READ:
          FD_SET(fd, &readFdSet);
          status = 1; // Wait for more activity
          break;
    
        case SSL_ERROR_ZERO_RETURN:
        case SSL_ERROR_SYSCALL:
          // The peer has notified us that it is shutting down via
          // the SSL "close_notify" message so we need to
          // shutdown, too.
          printf("Peer closed connection during SSL handshake,status:%d", status);
          status = -1;
          break;
        default:
          printf("Unexpected error during SSL handshake,status:%d", status);
          status = -1;
          break;
        }
    
        if (status == 1)
        {
          // Must have at least one handle to wait for at this point.
          status = select(fd + 1, &readFdSet, &writeFdSet, NULL, &tv);
    
          // 0 is timeout, so we're done.
          // -1 is error, so we're done.
          // Could be both handles set (same handle in both masks) so
          // set to 1.
          if (status >= 1)
          {
            status = 1;
          }
          else // Timeout or failure
          {
            printf("SSL handshake - peer timeout or failure");
            status = -1;
          }
        }
    
      }
      while (status == 1 && !SSL_is_init_finished(ssl));
    
      flags = fcntl(fd, F_GETFL, 0);
      if (flags < 0)
      {
        printf("fcntl: F_GETFL \n");
        return false;
      }
      if (fcntl(fd, F_SETFL, flags & (~O_NONBLOCK)) < 0)
      {
        printf("fcntl: F_SETFL \n");
        return false;
      }
    
    
      return (status >= 0);