diff options
author | Costa Tsaousis <costa@netdata.cloud> | 2023-06-20 21:55:51 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-20 21:55:51 +0300 |
commit | 16a4dc97f9f9726e8d54883211add9b0592529be (patch) | |
tree | df0ac85064bf09d1a5490aa8fdec17eda85555f2 /libnetdata | |
parent | a8da69781970b585e2b4af58f763dfb240445d92 (diff) |
Fix SSL non-blocking retry handling in the web server (#15222)
* readers should be able to recursively acquire the lock, even when there is a writer waiting
* log failure to establish connection
* debug log on streaming sender
* log the length of the message
* log recv_timeout()
* debug
* debug
* debug ssl read
* log SSL_get_error() responses
* handle EWOULDBLOCK in web_client_receive()
* make the web server handle EWOULDBLOCK case for SSL
* remove debug statements
* handle more errno values
Diffstat (limited to 'libnetdata')
-rw-r--r-- | libnetdata/socket/security.c | 151 | ||||
-rw-r--r-- | libnetdata/socket/security.h | 1 | ||||
-rw-r--r-- | libnetdata/socket/socket.c | 7 |
3 files changed, 84 insertions, 75 deletions
diff --git a/libnetdata/socket/security.c b/libnetdata/socket/security.c index 35c8c3adcf..fe7e5cbaf6 100644 --- a/libnetdata/socket/security.c +++ b/libnetdata/socket/security.c @@ -23,80 +23,19 @@ static SOCKET_PEERS netdata_ssl_peers(NETDATA_SSL *ssl) { return socket_peers(sock_fd); } -bool netdata_ssl_open(NETDATA_SSL *ssl, SSL_CTX *ctx, int fd) { - errno = 0; - ssl->ssl_errno = 0; - - if(ssl->conn) { - if(!ctx || SSL_get_SSL_CTX(ssl->conn) != ctx) { - SSL_free(ssl->conn); - ssl->conn = NULL; - } - else if (SSL_clear(ssl->conn) == 0) { - netdata_ssl_log_error_queue("SSL_clear", ssl); - SSL_free(ssl->conn); - ssl->conn = NULL; - } - } - - if(!ssl->conn) { - if(!ctx) { - internal_error(true, "SSL: not CTX given"); - ssl->state = NETDATA_SSL_STATE_FAILED; - return false; - } - - ssl->conn = SSL_new(ctx); - if (!ssl->conn) { - netdata_ssl_log_error_queue("SSL_new", ssl); - ssl->state = NETDATA_SSL_STATE_FAILED; - return false; - } - } - - if(SSL_set_fd(ssl->conn, fd) != 1) { - netdata_ssl_log_error_queue("SSL_set_fd", ssl); - ssl->state = NETDATA_SSL_STATE_FAILED; - return false; - } - - ssl->state = NETDATA_SSL_STATE_INIT; - - ERR_clear_error(); - - return true; -} - -void netdata_ssl_close(NETDATA_SSL *ssl) { - errno = 0; - ssl->ssl_errno = 0; - - if(ssl->conn) { - if(SSL_connection(ssl)) { - int ret = SSL_shutdown(ssl->conn); - if(ret == 0) - SSL_shutdown(ssl->conn); - } +static void netdata_ssl_log_error_queue(const char *call, NETDATA_SSL *ssl, unsigned long err) { + error_limit_static_thread_var(erl, 1, 0); - SSL_free(ssl->conn); + if(err == SSL_ERROR_NONE) + err = ERR_get_error(); - ERR_clear_error(); - } - - *ssl = NETDATA_SSL_UNSET_CONNECTION; -} + if(err == SSL_ERROR_NONE) + return; -void netdata_ssl_log_error_queue(const char *call, NETDATA_SSL *ssl) { - error_limit_static_thread_var(erl, 1, 0); - unsigned long err; - while((err = ERR_get_error())) { + do { char *code; switch (err) { - case SSL_ERROR_NONE: - code = "SSL_ERROR_NONE"; - break; - case SSL_ERROR_SSL: code = "SSL_ERROR_SSL"; ssl->state = NETDATA_SSL_STATE_FAILED; @@ -166,7 +105,71 @@ void netdata_ssl_log_error_queue(const char *call, NETDATA_SSL *ssl) { SOCKET_PEERS peers = netdata_ssl_peers(ssl); error_limit(&erl, "SSL: %s() on socket local [[%s]:%d] <-> remote [[%s]:%d], returned error %lu (%s): %s", call, peers.local.ip, peers.local.port, peers.peer.ip, peers.peer.port, err, code, str); + + } while((err = ERR_get_error())); +} + +bool netdata_ssl_open(NETDATA_SSL *ssl, SSL_CTX *ctx, int fd) { + errno = 0; + ssl->ssl_errno = 0; + + if(ssl->conn) { + if(!ctx || SSL_get_SSL_CTX(ssl->conn) != ctx) { + SSL_free(ssl->conn); + ssl->conn = NULL; + } + else if (SSL_clear(ssl->conn) == 0) { + netdata_ssl_log_error_queue("SSL_clear", ssl, SSL_ERROR_NONE); + SSL_free(ssl->conn); + ssl->conn = NULL; + } + } + + if(!ssl->conn) { + if(!ctx) { + internal_error(true, "SSL: not CTX given"); + ssl->state = NETDATA_SSL_STATE_FAILED; + return false; + } + + ssl->conn = SSL_new(ctx); + if (!ssl->conn) { + netdata_ssl_log_error_queue("SSL_new", ssl, SSL_ERROR_NONE); + ssl->state = NETDATA_SSL_STATE_FAILED; + return false; + } } + + if(SSL_set_fd(ssl->conn, fd) != 1) { + netdata_ssl_log_error_queue("SSL_set_fd", ssl, SSL_ERROR_NONE); + ssl->state = NETDATA_SSL_STATE_FAILED; + return false; + } + + ssl->state = NETDATA_SSL_STATE_INIT; + + ERR_clear_error(); + + return true; +} + +void netdata_ssl_close(NETDATA_SSL *ssl) { + errno = 0; + ssl->ssl_errno = 0; + + if(ssl->conn) { + if(SSL_connection(ssl)) { + int ret = SSL_shutdown(ssl->conn); + if(ret == 0) + SSL_shutdown(ssl->conn); + } + + SSL_free(ssl->conn); + + ERR_clear_error(); + } + + *ssl = NETDATA_SSL_UNSET_CONNECTION; } static inline bool is_handshake_complete(NETDATA_SSL *ssl, const char *op) { @@ -231,11 +234,12 @@ ssize_t netdata_ssl_read(NETDATA_SSL *ssl, void *buf, size_t num) { if(unlikely(bytes <= 0)) { int err = SSL_get_error(ssl->conn, bytes); - netdata_ssl_log_error_queue("SSL_read", ssl); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { ssl->ssl_errno = err; errno = EWOULDBLOCK; } + else + netdata_ssl_log_error_queue("SSL_read", ssl, err); bytes = -1; // according to read() or recv() } @@ -267,11 +271,12 @@ ssize_t netdata_ssl_write(NETDATA_SSL *ssl, const void *buf, size_t num) { if(unlikely(bytes <= 0)) { int err = SSL_get_error(ssl->conn, bytes); - netdata_ssl_log_error_queue("SSL_write", ssl); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { ssl->ssl_errno = err; errno = EWOULDBLOCK; } + else + netdata_ssl_log_error_queue("SSL_write", ssl, err); bytes = -1; // according to write() or send() } @@ -353,7 +358,8 @@ bool netdata_ssl_connect(NETDATA_SSL *ssl) { } if (err != 1) { - netdata_ssl_log_error_queue("SSL_connect", ssl); + err = SSL_get_error(ssl->conn, err); + netdata_ssl_log_error_queue("SSL_connect", ssl, err); ssl->state = NETDATA_SSL_STATE_FAILED; return false; } @@ -378,7 +384,8 @@ bool netdata_ssl_accept(NETDATA_SSL *ssl) { } if (err != 1) { - netdata_ssl_log_error_queue("SSL_accept", ssl); + err = SSL_get_error(ssl->conn, err); + netdata_ssl_log_error_queue("SSL_accept", ssl, err); ssl->state = NETDATA_SSL_STATE_FAILED; return false; } diff --git a/libnetdata/socket/security.h b/libnetdata/socket/security.h index c83b60ad1a..a4082a0776 100644 --- a/libnetdata/socket/security.h +++ b/libnetdata/socket/security.h @@ -65,7 +65,6 @@ bool netdata_ssl_accept(NETDATA_SSL *ssl); bool netdata_ssl_open(NETDATA_SSL *ssl, SSL_CTX *ctx, int fd); void netdata_ssl_close(NETDATA_SSL *ssl); -void netdata_ssl_log_error_queue(const char *call, NETDATA_SSL *ssl); ssize_t netdata_ssl_read(NETDATA_SSL *ssl, void *buf, size_t num); ssize_t netdata_ssl_write(NETDATA_SSL *ssl, const void *buf, size_t num); diff --git a/libnetdata/socket/socket.c b/libnetdata/socket/socket.c index daf1629a0e..f8927b4550 100644 --- a/libnetdata/socket/socket.c +++ b/libnetdata/socket/socket.c @@ -1052,19 +1052,22 @@ ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout) return -1; } - if(!retval) + if(!retval) { // timeout return 0; + } if(fd.revents & POLLIN) break; } #ifdef ENABLE_HTTPS - if (SSL_connection(ssl)) + if (SSL_connection(ssl)) { return netdata_ssl_read(ssl, buf, len); + } #endif + internal_error(true, "%s(): calling recv()", __FUNCTION__ ); return recv(sockfd, buf, len, flags); } |