diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c index ee392efb9d..36205a895c 100644 --- a/src/resolve/resolved-dns-stream.c +++ b/src/resolve/resolved-dns-stream.c @@ -36,6 +36,12 @@ static int dns_stream_update_io(DnsStream *s) { if (!s->read_packet || s->n_read < sizeof(s->read_size) + s->read_packet->size) f |= EPOLLIN; +#if ENABLE_DNS_OVER_TLS + /* For handshake and clean closing purposes, TLS can override requested events */ + if (s->dnstls_events) + f = s->dnstls_events; +#endif + return sd_event_source_set_io_events(s->io_event_source, f); } @@ -274,10 +280,17 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use if (s->encrypted) { r = dnstls_stream_on_io(s); - if (r == DNSTLS_STREAM_CLOSED || r == -EAGAIN) + if (r == DNSTLS_STREAM_CLOSED) return 0; - else if (r < 0) + else if (r == -EAGAIN) + return dns_stream_update_io(s); + else if (r < 0) { return dns_stream_complete(s, -r); + } else { + r = dns_stream_update_io(s); + if (r < 0) + return r; + } } #endif diff --git a/src/resolve/resolved-dns-stream.h b/src/resolve/resolved-dns-stream.h index d64dc3b1d4..72db2a1a56 100644 --- a/src/resolve/resolved-dns-stream.h +++ b/src/resolve/resolved-dns-stream.h @@ -42,6 +42,7 @@ struct DnsStream { #if ENABLE_DNS_OVER_TLS DnsTlsStreamData dnstls_data; + int dnstls_events; #endif sd_event_source *io_event_source; diff --git a/src/resolve/resolved-dnstls-gnutls.c b/src/resolve/resolved-dnstls-gnutls.c index 9c348cef67..36ee570b46 100644 --- a/src/resolve/resolved-dnstls-gnutls.c +++ b/src/resolve/resolved-dnstls-gnutls.c @@ -86,23 +86,28 @@ int dnstls_stream_on_io(DnsStream *stream) { if (stream->dnstls_data.shutdown) { r = gnutls_bye(stream->dnstls_data.session, GNUTLS_SHUT_RDWR); - if (r == GNUTLS_E_AGAIN) + if (r == GNUTLS_E_AGAIN) { + stream->dnstls_events = gnutls_record_get_direction(stream->dnstls_data.session) == 1 ? EPOLLOUT : EPOLLIN; return -EAGAIN; - else if (r < 0) + } else if (r < 0) log_debug("Failed to invoke gnutls_bye: %s", gnutls_strerror(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) { stream->dnstls_data.handshake = gnutls_handshake(stream->dnstls_data.session); - if (stream->dnstls_data.handshake == GNUTLS_E_AGAIN) + if (stream->dnstls_data.handshake == GNUTLS_E_AGAIN) { + stream->dnstls_events = gnutls_record_get_direction(stream->dnstls_data.session) == 1 ? EPOLLOUT : EPOLLIN; return -EAGAIN; - else if (stream->dnstls_data.handshake < 0) { + } else if (stream->dnstls_data.handshake < 0) { log_debug("Failed to invoke gnutls_handshake: %s", gnutls_strerror(stream->dnstls_data.handshake)); if (gnutls_error_is_fatal(stream->dnstls_data.handshake)) return -ECONNREFUSED; } + + stream->dnstls_events = 0; } return 0;