diff --git a/src/resolve/resolved-dnstls-openssl.c b/src/resolve/resolved-dnstls-openssl.c index 5dd7737337..a7a8b1152a 100644 --- a/src/resolve/resolved-dnstls-openssl.c +++ b/src/resolve/resolved-dnstls-openssl.c @@ -46,11 +46,9 @@ static int dnstls_flush_write_buffer(DnsStream *stream) { } int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) { + _cleanup_(BIO_freep) BIO *rb = NULL, *wb = NULL; _cleanup_(SSL_freep) SSL *s = NULL; - _cleanup_(BIO_freep) BIO *rb = NULL; - _cleanup_(BIO_freep) BIO *wb = NULL; - int r; - int error; + int error, r; assert(stream); assert(server); @@ -73,6 +71,7 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) { SSL_set_session(s, server->dnstls_data.session); SSL_set_bio(s, TAKE_PTR(rb), TAKE_PTR(wb)); + ERR_clear_error(); stream->dnstls_data.handshake = SSL_do_handshake(s); if (stream->dnstls_data.handshake <= 0) { error = SSL_get_error(s, stream->dnstls_data.handshake); @@ -105,14 +104,13 @@ void dnstls_stream_free(DnsStream *stream) { } int dnstls_stream_on_io(DnsStream *stream, uint32_t revents) { - int r; - int error; + int error, r; assert(stream); assert(stream->encrypted); assert(stream->dnstls_data.ssl); - /* Flush write buffer when requested by OpenSSL ss*/ + /* Flush write buffer when requested by OpenSSL */ if ((revents & EPOLLOUT) && (stream->dnstls_events & EPOLLOUT)) { r = dnstls_flush_write_buffer(stream); if (r < 0) @@ -120,35 +118,48 @@ int dnstls_stream_on_io(DnsStream *stream, uint32_t revents) { } if (stream->dnstls_data.shutdown) { + ERR_clear_error(); r = SSL_shutdown(stream->dnstls_data.ssl); - if (r <= 0) { + if (r == 0) { + stream->dnstls_events = 0; + + r = dnstls_flush_write_buffer(stream); + if (r < 0) + return r; + + return -EAGAIN; + } else if (r < 0) { error = SSL_get_error(stream->dnstls_data.ssl, r); - if (r == 0 || IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) { - if (r < 0) - stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT; + if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) { + stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT; r = dnstls_flush_write_buffer(stream); if (r < 0) return r; return -EAGAIN; + } else if (error == SSL_ERROR_SYSCALL) { + if (errno > 0) + log_debug_errno(errno, "Failed to invoke SSL_shutdown, ignoring: %m"); } else { char errbuf[256]; ERR_error_string_n(error, errbuf, sizeof(errbuf)); - log_debug("Failed to invoke SSL_shutdown: %s", errbuf); + log_debug("Failed to invoke SSL_shutdown, ignoring: %s", errbuf); } } + stream->dnstls_events = 0; + stream->dnstls_data.shutdown = false; + r = dnstls_flush_write_buffer(stream); if (r < 0) return r; - stream->dnstls_events = 0; - stream->dnstls_data.shutdown = false; dns_stream_unref(stream); return DNSTLS_STREAM_CLOSED; } else if (stream->dnstls_data.handshake <= 0) { + ERR_clear_error(); stream->dnstls_data.handshake = SSL_do_handshake(stream->dnstls_data.ssl); if (stream->dnstls_data.handshake <= 0) { error = SSL_get_error(stream->dnstls_data.ssl, stream->dnstls_data.handshake); @@ -178,8 +189,7 @@ int dnstls_stream_on_io(DnsStream *stream, uint32_t revents) { } int dnstls_stream_shutdown(DnsStream *stream, int error) { - int r; - int ssl_error; + int ssl_error, r; SSL_SESSION *s; assert(stream); @@ -197,6 +207,7 @@ int dnstls_stream_shutdown(DnsStream *stream, int error) { } if (error == ETIMEDOUT) { + ERR_clear_error(); r = SSL_shutdown(stream->dnstls_data.ssl); if (r == 0) { if (!stream->dnstls_data.shutdown) { @@ -204,6 +215,8 @@ int dnstls_stream_shutdown(DnsStream *stream, int error) { dns_stream_ref(stream); } + stream->dnstls_events = 0; + r = dnstls_flush_write_buffer(stream); if (r < 0) return r; @@ -222,11 +235,14 @@ int dnstls_stream_shutdown(DnsStream *stream, int error) { dns_stream_ref(stream); } return -EAGAIN; + } else if (ssl_error == SSL_ERROR_SYSCALL) { + if (errno > 0) + log_debug_errno(errno, "Failed to invoke SSL_shutdown, ignoring: %m"); } else { char errbuf[256]; ERR_error_string_n(ssl_error, errbuf, sizeof(errbuf)); - log_debug("Failed to invoke SSL_shutdown: %s", errbuf); + log_debug("Failed to invoke SSL_shutdown, ignoring: %s", errbuf); } } @@ -240,8 +256,7 @@ int dnstls_stream_shutdown(DnsStream *stream, int error) { } ssize_t dnstls_stream_write(DnsStream *stream, const char *buf, size_t count) { - int r; - int error; + int error, r; ssize_t ss; assert(stream); @@ -249,26 +264,27 @@ ssize_t dnstls_stream_write(DnsStream *stream, const char *buf, size_t count) { assert(stream->dnstls_data.ssl); assert(buf); + ERR_clear_error(); ss = r = SSL_write(stream->dnstls_data.ssl, buf, count); if (r <= 0) { - error = SSL_get_error(stream->dnstls_data.ssl, ss); + error = SSL_get_error(stream->dnstls_data.ssl, r); if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) { stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT; - r = dnstls_flush_write_buffer(stream); - if (r < 0) - return r; - ss = -EAGAIN; + } else if (error == SSL_ERROR_ZERO_RETURN) { + stream->dnstls_events = 0; + ss = 0; } else { char errbuf[256]; ERR_error_string_n(error, errbuf, sizeof(errbuf)); - log_debug("Failed to invoke SSL_read: %s", errbuf); + log_debug("Failed to invoke SSL_write: %s", errbuf); + stream->dnstls_events = 0; ss = -EPIPE; } - } + } else + stream->dnstls_events = 0; - stream->dnstls_events = 0; r = dnstls_flush_write_buffer(stream); if (r < 0) return r; @@ -277,8 +293,7 @@ ssize_t dnstls_stream_write(DnsStream *stream, const char *buf, size_t count) { } ssize_t dnstls_stream_read(DnsStream *stream, void *buf, size_t count) { - int r; - int error; + int error, r; ssize_t ss; assert(stream); @@ -286,28 +301,26 @@ ssize_t dnstls_stream_read(DnsStream *stream, void *buf, size_t count) { assert(stream->dnstls_data.ssl); assert(buf); + ERR_clear_error(); ss = r = SSL_read(stream->dnstls_data.ssl, buf, count); if (r <= 0) { - error = SSL_get_error(stream->dnstls_data.ssl, ss); + error = SSL_get_error(stream->dnstls_data.ssl, r); if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) { stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT; - - /* flush write buffer in cache of renegotiation */ - r = dnstls_flush_write_buffer(stream); - if (r < 0) - return r; - ss = -EAGAIN; + } else if (error == SSL_ERROR_ZERO_RETURN) { + stream->dnstls_events = 0; + ss = 0; } else { char errbuf[256]; ERR_error_string_n(error, errbuf, sizeof(errbuf)); log_debug("Failed to invoke SSL_read: %s", errbuf); + stream->dnstls_events = 0; ss = -EPIPE; } - } - - stream->dnstls_events = 0; + } else + stream->dnstls_events = 0; /* flush write buffer in cache of renegotiation */ r = dnstls_flush_write_buffer(stream);