make outgoing SSL_connect() non-blocking
authorAlan T. DeKok <aland@freeradius.org>
Thu, 25 May 2017 20:59:14 +0000 (16:59 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 25 May 2017 20:59:37 +0000 (16:59 -0400)
src/include/tls-h
src/main/listen.c
src/main/tls.c
src/main/tls_listen.c

index 095ef1f..6c4629b 100644 (file)
@@ -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
index b277c6b..61c299e 100644 (file)
@@ -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",
index c21c5f1..ce7799e 100644 (file)
@@ -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;
 }
 
index 2644a4e..785b243 100644 (file)
@@ -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);