2009-11-16 4 views
0

SSL을 사용하여 서버를 만들고 소켓을 차단했습니다. 텔넷으로 연결할 때 (핸드 셰이크를하지 않기 때문에) SSL_accept는 무기한 차단하고 새로운 핸드 셰이크/수락 (그리고 정의에 따라 새 연결)을 차단합니다.블로킹 소켓이있는 SSL_accept

이 끔찍한 문제를 어떻게 해결할 수 있습니까?

답변

1

은 왜 그냥 SSL_accept()를 호출하기 전에 비 블록 모드의 소켓 스트림을 설정하고 SSL_accept()가 SSL_ERROR_WANT_READ 또는 SSL_ERROR_WANT_WRITE을 반환하는 경우 다음 타임 아웃 select() 같은에 차단? 또는 SSL_accept()를 호출하기 전에 select()를 차단할 수 있습니다. 어느 쪽이든 작동해야합니다. 그렇게하면 최소한 행동/공격과 같은 DoS으로 인해 연결이 차단 된 시간을 제한 할 수 있습니다.

SSL/TLS는 레코드 지향이므로 전체 레코드를 읽을 때까지 반복해야한다는 것을 명심하십시오. 그러한 경우에는 SSL_pending()이 도움이 될 수 있습니다.

1

텔넷으로 연결하지 마십시오?

일반적으로 TLS 또는 일반 텍스트 연결을 사용할 수있는 서비스는 일반 텍스트로 연결을 설정 한 다음 TLS를 사용하도록 연결을 "업그레이드"하도록 요청하는 명령을 제공하여 작동합니다. 확장 SMTP 및 "STARTTLS"명령은이 예입니다.

이러한 명령이없는 서비스는 일반적으로 TLS 및 비 TLS 트래픽에 대해 고유 한 포트를 사용합니다. 예를 들어 포트 80에서는 HTTP, 포트 443에서는 HTTPS가 사용됩니다. 포트 443에 대한 일반 텍스트 연결은 작동하지 않습니다.

어떤 행동을 보시겠습니까?

+0

그래, 그게 내가하고있는 일이지만 핸드 셰이크를 할 때 클라이언트의 연결을 끊을 때마다 다른 핸드 셰이크를 차단한다고 상상해보십시오. 는 말은 : -는 TCP가 메인 스레드 에서 이루어집니다 동의 - SSL_accept 각 새 스레드 에 의해 이루어집니다 - (별도의 스레드에서) 하나 개의 핸드 셰이크 블록은 블록의 경우 모든 핸드 셰이크 내가하고 싶은 행동 모든 새로운 악수를 차단하는 것이 아니다. – fedj

0

소켓을 비 차단 모드로 놓으면 SSL_ERROR_WANT_READ 또는 SSL_ERROR_WANT_WRITE가 SSL_accept에서 가져옵니다. 그런 다음 조금 잠을 자면 SSL_accept를 다시 시도하십시오. 일부 시간 초과 값 후에는 종료하고 ssl 및 소켓 핸들을 닫을 수 있습니다.

모든 SSL 작업에 영향을 미치므로 모든 읽기/쓰기/종료 호출에 대해 유사한 루프를 수행해야합니다. 기본적으로 WANT_READ 또는 WANT_WRITE를 반환 할 수있는 모든 호출.

폴링 아이디어가 마음에 들지 않으면 select를 사용하여 소켓에서 사용할 수있는 데이터가 있는지 알아낼 수 있지만 약간 복잡 할 수 있습니다.

또한 SSL_accept 루프 이후에 소켓을 다시 차단 모드로 전환하여 응용 프로그램을 계속 시도 할 수 있습니다.

0

아래 코드는 다른 사람들이 문제를 해결하는 데 도움이 될 것으로 생각합니다. 그것을 영감으로 받아 들일만큼 충분히 테스트되지는 않았습니다.

//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);