From 8391d0ba8ebd2599212317259d26a17cfebb5b2a Mon Sep 17 00:00:00 2001 From: "Alan T. DeKok" Date: Thu, 25 May 2017 16:59:14 -0400 Subject: [PATCH] make outgoing SSL_connect() non-blocking --- src/include/tls-h | 1 + src/main/listen.c | 11 ++--------- src/main/tls.c | 19 ++++++++++++++++-- src/main/tls_listen.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 11 deletions(-) diff --git a/src/include/tls-h b/src/include/tls-h index 095ef1f..6c4629b 100644 --- a/src/include/tls-h +++ b/src/include/tls-h @@ -137,6 +137,7 @@ typedef struct _tls_session_t { unsigned int (*record_minus)(record_t *buf, void *ptr, unsigned int size); bool invalid_hb_used; //!< Whether heartbleed attack was detected. + bool connected; //!< whether the outgoing socket is connected /* * Framed-MTU attribute in RADIUS, if present, can also be used to set this diff --git a/src/main/listen.c b/src/main/listen.c index b277c6b..61c299e 100644 --- a/src/main/listen.c +++ b/src/main/listen.c @@ -2623,18 +2623,11 @@ static int listen_bind(rad_listen_t *this) #ifdef WITH_TCP if (sock->proto == IPPROTO_TCP) { /* - * If there are hard-coded worker threads, OR - * it's a TLS connection, it's blocking. + * Woker threads are blocking. * * Otherwise, they're non-blocking. */ - if (!this->workers -#ifdef WITH_PROXY -#ifdef WITH_TLS - && (this->type == RAD_LISTEN_PROXY) && !this->tls -#endif -#endif - ) { + if (!this->workers) { if (fr_nonblock(this->fd) < 0) { close(this->fd); ERROR("Failed setting non-blocking on socket: %s", diff --git a/src/main/tls.c b/src/main/tls.c index c21c5f1..ce7799e 100644 --- a/src/main/tls.c +++ b/src/main/tls.c @@ -505,6 +505,7 @@ tls_session_t *tls_new_client_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *con talloc_set_destructor(ssn, _tls_session_free); ssn->ctx = conf->ctx; + ssn->mtu = conf->fragment_size; SSL_CTX_set_mode(ssn->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_AUTO_RETRY); @@ -537,6 +538,21 @@ tls_session_t *tls_new_client_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *con SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_SSN, (void *)ssn); SSL_set_fd(ssn->ssl, fd); ret = SSL_connect(ssn->ssl); + + if (ret < 0) { + switch (SSL_get_error(ssn->ssl, ret)) { + default: + break; + + + + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + ssn->connected = false; + return ssn; + } + } + if (ret <= 0) { tls_error_io_log(NULL, ssn, ret, "Failed in " STRINGIFY(__FUNCTION__) " (SSL_connect)"); talloc_free(ssn); @@ -544,8 +560,7 @@ tls_session_t *tls_new_client_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *con return NULL; } - ssn->mtu = conf->fragment_size; - + ssn->connected = true; return ssn; } diff --git a/src/main/tls_listen.c b/src/main/tls_listen.c index 2644a4e..785b243 100644 --- a/src/main/tls_listen.c +++ b/src/main/tls_listen.c @@ -479,6 +479,34 @@ int dual_tls_send(rad_listen_t *listener, REQUEST *request) return 0; } +static int try_connect(tls_session_t *ssn) +{ + int ret; + ret = SSL_connect(ssn->ssl); + if (ret < 0) { + switch (SSL_get_error(ssn->ssl, ret)) { + default: + break; + + + + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + ssn->connected = false; + return 0; + } + } + + if (ret <= 0) { + tls_error_io_log(NULL, ssn, ret, "Failed in " STRINGIFY(__FUNCTION__) " (SSL_connect)"); + talloc_free(ssn); + + return -1; + } + + return 1; +} + #ifdef WITH_PROXY /* @@ -500,6 +528,18 @@ static ssize_t proxy_tls_read(rad_listen_t *listener) uint8_t *data; listen_socket_t *sock = listener->data; + if (!sock->ssn->connected) { + rcode = try_connect(sock->ssn); + if (rcode == 0) return 0; + + if (rcode < 0) { + SSL_shutdown(sock->ssn->ssl); + return -1; + } + + sock->ssn->connected = true; + } + /* * Get the maximum size of data to receive. */ @@ -693,6 +733,20 @@ int proxy_tls_send(rad_listen_t *listener, REQUEST *request) request); } + if (!sock->ssn->connected) { + PTHREAD_MUTEX_LOCK(&sock->mutex); + rcode = try_connect(sock->ssn); + PTHREAD_MUTEX_LOCK(&sock->mutex); + if (rcode == 0) return 0; + + if (rcode < 0) { + SSL_shutdown(sock->ssn->ssl); + return -1; + } + + sock->ssn->connected = true; + } + DEBUG3("Proxy is writing %u bytes to SSL", (unsigned int) request->proxy->data_len); PTHREAD_MUTEX_LOCK(&sock->mutex); -- 2.1.4