1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-25 17:48:48 -05:00

ssl: read pending close notify alert before closing the connection

This avoids a TCP reset (RST) if the server initiates a connection
shutdown by sending an SSL close notify alert and then closes the TCP
connection.

For SSL connections, usually the server announces that it will close the
connection with an SSL close notify alert. curl should read this alert.
If curl does not read this alert and just closes the connection, some
operating systems close the TCP connection with an RST flag.

See RFC 1122, section 4.2.2.13

If curl reads the close notify alert, the TCP connection is closed
normally with a FIN flag.

The new code is similar to existing code in the "SSL shutdown" function:
try to read an alert (non-blocking), and ignore any read errors.

Closes #7095
This commit is contained in:
Michael Kaufmann 2021-05-18 11:34:02 +02:00
parent 8cc1fee5b9
commit b249592d29
5 changed files with 28 additions and 1 deletions

View File

@ -1438,6 +1438,10 @@ static void close_one(struct ssl_connect_data *connssl)
{ {
struct ssl_backend_data *backend = connssl->backend; struct ssl_backend_data *backend = connssl->backend;
if(backend->session) { if(backend->session) {
char buf[32];
/* Maybe the server has already sent a close notify alert.
Read it to avoid an RST on the TCP connection. */
(void)gnutls_record_recv(backend->session, buf, sizeof(buf));
gnutls_bye(backend->session, GNUTLS_SHUT_WR); gnutls_bye(backend->session, GNUTLS_SHUT_WR);
gnutls_deinit(backend->session); gnutls_deinit(backend->session);
backend->session = NULL; backend->session = NULL;

View File

@ -813,8 +813,13 @@ static void mbedtls_close(struct Curl_easy *data,
{ {
struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend; struct ssl_backend_data *backend = connssl->backend;
char buf[32];
(void) data; (void) data;
/* Maybe the server has already sent a close notify alert.
Read it to avoid an RST on the TCP connection. */
(void)mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, sizeof(buf));
mbedtls_pk_free(&backend->pk); mbedtls_pk_free(&backend->pk);
mbedtls_x509_crt_free(&backend->clicert); mbedtls_x509_crt_free(&backend->clicert);
mbedtls_x509_crt_free(&backend->cacert); mbedtls_x509_crt_free(&backend->cacert);

View File

@ -1546,6 +1546,14 @@ static void close_one(struct ssl_connect_data *connssl)
const bool client_cert = (backend->client_nickname != NULL) const bool client_cert = (backend->client_nickname != NULL)
|| (backend->obj_clicert != NULL); || (backend->obj_clicert != NULL);
if(backend->handle) {
char buf[32];
/* Maybe the server has already sent a close notify alert.
Read it to avoid an RST on the TCP connection. */
(void)PR_Recv(backend->handle, buf, (int)sizeof(buf), 0,
PR_INTERVAL_NO_WAIT);
}
free(backend->client_nickname); free(backend->client_nickname);
backend->client_nickname = NULL; backend->client_nickname = NULL;

View File

@ -1400,7 +1400,13 @@ static void ossl_closeone(struct Curl_easy *data,
{ {
struct ssl_backend_data *backend = connssl->backend; struct ssl_backend_data *backend = connssl->backend;
if(backend->handle) { if(backend->handle) {
char buf[32];
set_logger(conn, data); set_logger(conn, data);
/* Maybe the server has already sent a close notify alert.
Read it to avoid an RST on the TCP connection. */
(void)SSL_read(backend->handle, buf, (int)sizeof(buf));
(void)SSL_shutdown(backend->handle); (void)SSL_shutdown(backend->handle);
SSL_set_connect_state(backend->handle); SSL_set_connect_state(backend->handle);

View File

@ -810,6 +810,10 @@ static void wolfssl_close(struct Curl_easy *data, struct connectdata *conn,
(void) data; (void) data;
if(backend->handle) { if(backend->handle) {
char buf[32];
/* Maybe the server has already sent a close notify alert.
Read it to avoid an RST on the TCP connection. */
(void)SSL_read(backend->handle, buf, (int)sizeof(buf));
(void)SSL_shutdown(backend->handle); (void)SSL_shutdown(backend->handle);
SSL_free(backend->handle); SSL_free(backend->handle);
backend->handle = NULL; backend->handle = NULL;