Merge pull request #9787 from yuwata/dns-over-tls-log

DNS-over-TLS(openssl): fix error handling
This commit is contained in:
Lennart Poettering 2018-08-03 13:11:18 +02:00 committed by GitHub
commit 4103c950ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 52 additions and 39 deletions

View File

@ -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);