簡體   English   中英

如何為 BIO_do_connect 設置超時?

[英]How to set a timeout for BIO_do_connect?

我在這里找到了一個 SSL/TLS 客戶端示例,它運行良好。

#include <stdio.h>
#include <errno.h>
#include <malloc.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>
#include <openssl/ssl.h>
#include <openssl/conf.h>

void connect(const char* host, int port) {
    BIO* sbio, * out;
    int len;
    char tmpbuf[1024];
    SSL_CTX* ctx;
    SSL* ssl;
    char server[200];
    snprintf(server, sizeof(server), "%s:%d", host, port);
    /* XXX Seed the PRNG if needed. */
    ctx = SSL_CTX_new(TLS_client_method());
    /* XXX Set verify paths and mode here. */
    sbio = BIO_new_ssl_connect(ctx);
    BIO_get_ssl(sbio, &ssl);
    if (ssl == NULL) {
        fprintf(stderr, "Can't locate SSL pointer\n");
        ERR_print_errors_fp(stderr);
        exit(1);
    }
    /* Don't want any retries */
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
    /* XXX We might want to do other things with ssl here */
    /* An empty host part means the loopback address */
    BIO_set_conn_hostname(sbio, server);
    out = BIO_new_fp(stdout, BIO_NOCLOSE);
    if (BIO_do_connect(sbio) <= 0) {
        fprintf(stderr, "Error connecting to server\n");
        ERR_print_errors_fp(stderr);
        exit(1);
    }
    int ret = 0;
    if ((ret = BIO_do_handshake(sbio)) <= 0) {
        fprintf(stderr, "Error establishing SSL connection\n");
        ERR_print_errors_fp(stderr);
        exit(1);
    }
    /* XXX Could examine ssl here to get connection info */
    BIO_puts(sbio, "Hi, this message is from client c++");
    for (;;) {
        len = BIO_read(sbio, tmpbuf, 1024);
        if (len <= 0) {
            break;
        }
        BIO_write(out, tmpbuf, len);
    }
    BIO_free_all(sbio);
    BIO_free(out);
}
int main() {
    connect("127.0.0.1", 5555);
}

但我需要為此連接設置超時。 然后我發現如何在 OpenSSL 中設置連接超時和操作超時 所以我改變了代碼

    if (BIO_do_connect(sbio) <= 0) {
        fprintf(stderr, "Error connecting to server\n");
        ERR_print_errors_fp(stderr);
        exit(1);
    }

    {
        BIO_set_nbio(sbio, 1);
        if (1 > BIO_do_connect(sbio)) {
            if (!BIO_should_retry(sbio)) {
                fprintf(stderr, "Error: should not retry\n");
                ERR_print_errors_fp(stderr);
                exit(1);
            }
            int fdSocket = 0;
            if (BIO_get_fd(sbio, &fdSocket) < 0) {
                fprintf(stderr, "Error: can not get socket\n");
                ERR_print_errors_fp(stderr);
                exit(1);
            }
            struct timeval timeout;
            fd_set connectionfds;
            FD_ZERO(&connectionfds);
            FD_SET(fdSocket, &connectionfds);
            timeout.tv_usec = 0;
            timeout.tv_sec = 4;
            if (0 == select(fdSocket + 1, NULL, &connectionfds, NULL, &timeout)) {
                fprintf(stderr, "Error: timeout\n");
                ERR_print_errors_fp(stderr);
                exit(1);
            }
        }
    }

現在 BIO_do_handshake 返回 -1 並且程序退出。 在此處輸入圖像描述

如何為我的 ssl 連接正確設置超時?

請給我一些建議! 幫我!

我會分兩步 go 關於這個:

  1. 我會自己處理連接設置。 這樣您就可以使用非阻塞套接字、 connect(2)select(2)並完全控制這部分的時間。
  2. 我也會通過自己的 BIO 來實現。 您可以使用現有的 BIO 並僅實現readwriteputs方法。 這將允許您控制套接字訪問。

有了這個,您可以完全控制您花費的時間。 您可以為 session 設置、重新協商、正常操作實現不同的超時...

BIO_set_nbio 的問題在於您將 I/O 設置為非阻塞模式。 所以你必須在非阻塞模式下處理進一步的步驟。 我舉了一個例子,如何在sleep和非阻塞模式下處理請求。 也許它有點難看。 但它對我有用。

#include <openssl/err.h>
#include <openssl/ssl.h>

#include <unistd.h>
#include <stdio.h>


void connect(const char* host, int port) {
    const long timeout_nsec = 4 * (long)1000000000, dt_nsec = 100000;

    char tmpbuf[1024];

    char server[200];
    snprintf(server, sizeof(server), "%s:%d", host, port);
    
    struct timespec dt;
    dt.tv_sec = 0;
    dt.tv_nsec = dt_nsec;

    /* XXX Seed the PRNG if needed. */
    SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());
    /* XXX Set verify paths and mode here. */
    BIO *sbio = BIO_new_ssl_connect(ctx);

    SSL* ssl = nullptr;
    BIO_get_ssl(sbio, &ssl);
    if (ssl == NULL) {
        fprintf(stderr, "Can't locate SSL pointer\n");
        ERR_print_errors_fp(stderr);
        exit(1);
    }
    /* Don't want any retries */
    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
    /* XXX We might want to do other things with ssl here */
    /* An empty host part means the loopback address */
    BIO_set_conn_hostname(sbio, server);
    BIO *out = BIO_new_fp(stdout, BIO_NOCLOSE);
    
    BIO_set_nbio(sbio, 1);

    {
        long time_remained = timeout_nsec;
        while(1) {
            int res = BIO_do_connect(sbio);
            if (res <= 0 && BIO_should_retry(sbio)) {
                clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &dt, NULL);
                time_remained -= dt_nsec;
                if (time_remained <= 0) {
                    fprintf(stderr, "Timeout\n");
                    exit(1);
                }
                continue;
            }
            if (res <= 0) {
                fprintf(stderr, "BIO_do_connect error\n");
                ERR_print_errors_fp(stderr);
                exit(1);
            }
            break;
        }
    }

    {
        long time_remained = timeout_nsec;
        while(1) {
            int res = BIO_do_handshake(sbio);
            if (res <= 0 && BIO_should_retry(sbio)) {
                clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &dt, NULL);
                time_remained -= dt_nsec;
                if (time_remained <= 0) {
                    fprintf(stderr, "Timeout\n");
                    exit(1);
                }
                continue;
            }
            if (res <= 0) {
                fprintf(stderr, "BIO_do_handshake error\n");
                ERR_print_errors_fp(stderr);
                exit(1);
            }
            break;
        }
    }

    /* XXX Could examine ssl here to get connection info */
    int a = BIO_puts(sbio, "Hi, this message is from client c++");
    for (;;) {
        int len = -1;
        {
            long time_remained = timeout_nsec;
            while(1) {
                len = BIO_read(sbio, tmpbuf, 1024);
                if (len < 0 && BIO_should_retry(sbio)) {
                    clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &dt, NULL);
                    time_remained -= dt_nsec;
                    if (time_remained <= 0) {
                        fprintf(stderr, "Timeout\n");
                        exit(1);
                    }
                    continue;
                }
                if (len < 0) {
                    fprintf(stderr, "BIO_read error\n");
                    ERR_print_errors_fp(stderr);
                    exit(1);
                }
                break;
            }
        }
        if (len == 0) {
            break;
        }
        BIO_write(out, tmpbuf, len);
    }

    BIO_free_all(sbio);
    BIO_free(out);
}

int main() {
    connect("127.0.0.1", 5555);
}

我認為您應該為握手設置超時,而不是連接。 在您的代碼中,連接沒有問題,因為“選擇”返回非零值。 實際上 BIO_do_connect 在連接可用后會進行握手。 BIO_do_connect 和 BIO_do_handshake 在 header 文件中是相同的。

#  define BIO_do_connect(b)       BIO_do_handshake(b)

所以我認為這個問題是握手。 例如。 您連接到使用沒有 ssl 的普通 tcp 套接字的服務器。 服務器不會發送“server_hallo”和證書。 然后客戶端將等待這些“server_hallo”和證書。 如果握手過程仍未完成,BIO_do_handshake 返回 -1。 也許您可以使用BIO_set_ssl_renegotiate_timeout設置超時。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM