]> source.dussan.org Git - rspamd.git/commitdiff
[Minor] Try harder to do a "proper" SSL shutdown
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 11 Sep 2018 17:13:10 +0000 (18:13 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 11 Sep 2018 17:13:10 +0000 (18:13 +0100)
src/libutil/ssl_util.c

index 1eab5821f1cdb08392ce7257e57959b62ae5d7e7..09ce9b01b6947b3659b843b290953e477c4bc5f4 100644 (file)
 #include <openssl/conf.h>
 #include <openssl/x509v3.h>
 
+enum rspamd_ssl_state {
+       ssl_conn_reset = 0,
+       ssl_conn_init,
+       ssl_conn_connected,
+       ssl_next_read,
+       ssl_next_write
+};
+
+enum rspamd_ssl_shutdown {
+       ssl_shut_default = 0,
+       ssl_shut_unclean,
+};
+
 struct rspamd_ssl_connection {
        gint fd;
-       enum {
-               ssl_conn_reset = 0,
-               ssl_conn_init,
-               ssl_conn_connected,
-               ssl_next_read,
-               ssl_next_write
-       } state;
+       enum rspamd_ssl_state state;
+       enum rspamd_ssl_shutdown shut;
        gboolean verify_peer;
        SSL *ssl;
        gchar *hostname;
@@ -399,6 +407,10 @@ rspamd_ssl_event_handler (gint fd, short what, gpointer ud)
        gint ret;
        GError *err = NULL;
 
+       if (what == EV_TIMEOUT) {
+               c->shut = ssl_shut_unclean;
+       }
+
        switch (c->state) {
        case ssl_conn_init:
                /* Continue connection */
@@ -544,6 +556,8 @@ rspamd_ssl_connect_fd (struct rspamd_ssl_connection *conn, gint fd,
                        what = EV_WRITE;
                }
                else {
+                       conn->shut = ssl_shut_unclean;
+
                        return FALSE;
                }
 
@@ -573,6 +587,7 @@ rspamd_ssl_read (struct rspamd_ssl_connection *conn, gpointer buf,
                errno = EINVAL;
                g_set_error (&err, rspamd_ssl_quark (), ECONNRESET,
                                "ssl state error: cannot read data");
+               conn->shut = ssl_shut_unclean;
                conn->err_handler (conn->handler_data, err);
                g_error_free (err);
 
@@ -593,6 +608,7 @@ rspamd_ssl_read (struct rspamd_ssl_connection *conn, gpointer buf,
                        return 0;
                }
                else {
+                       conn->shut = ssl_shut_unclean;
                        rspamd_tls_set_error (ret, "read", &err);
                        conn->err_handler (conn->handler_data, err);
                        g_error_free (err);
@@ -613,6 +629,7 @@ rspamd_ssl_read (struct rspamd_ssl_connection *conn, gpointer buf,
                        what |= EV_WRITE;
                }
                else {
+                       conn->shut = ssl_shut_unclean;
                        rspamd_tls_set_error (ret, "read", &err);
                        conn->err_handler (conn->handler_data, err);
                        g_error_free (err);
@@ -667,6 +684,7 @@ rspamd_ssl_write (struct rspamd_ssl_connection *conn, gconstpointer buf,
                        return -1;
                }
                else {
+                       conn->shut = ssl_shut_unclean;
                        rspamd_tls_set_error (ret, "write", &err);
                        conn->err_handler (conn->handler_data, err);
                        g_error_free (err);
@@ -686,6 +704,7 @@ rspamd_ssl_write (struct rspamd_ssl_connection *conn, gconstpointer buf,
                        what = EV_WRITE;
                }
                else {
+                       conn->shut = ssl_shut_unclean;
                        rspamd_tls_set_error (ret, "write", &err);
                        conn->err_handler (conn->handler_data, err);
                        g_error_free (err);
@@ -757,8 +776,21 @@ rspamd_ssl_connection_free (struct rspamd_ssl_connection *conn)
                 * if the socket is not ready for writing, in which case this hack will
                 * lead to an unclean shutdown and lost session on the other end.
                 */
-               SSL_set_shutdown (conn->ssl, SSL_RECEIVED_SHUTDOWN);
-               SSL_shutdown (conn->ssl);
+               if (conn->shut == ssl_shut_unclean) {
+                       SSL_set_shutdown (conn->ssl, SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN);
+                       SSL_set_quiet_shutdown (conn->ssl, 1);
+               }
+               else {
+                       SSL_set_shutdown (conn->ssl, SSL_RECEIVED_SHUTDOWN);
+               }
+
+               /* Stupid hack to enforce SSL to do shutdown sequence */
+               for (guint i = 0; i < 4; i++) {
+                       if (SSL_shutdown (conn->ssl)) {
+                               break;
+                       }
+               }
+
                SSL_free (conn->ssl);
 
                if (conn->hostname) {