mirror of
https://github.com/systemd/systemd.git
synced 2024-12-25 01:34:28 +03:00
resolved: set io events after receiving EAGAIN for TLS
During handshake and TLS session closing, messages needs to be exchanged. Therefore this patch overrides the requested IO events for the TCP stream when the TLS is waiting for sending or receiving of messages during theses periods. This fixes issues with correctly closing the TLS stream and prevents the handshake from hanging in rare cases (not seen yet).
This commit is contained in:
parent
6016fcb0ea
commit
ba6aaf5727
@ -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
|
||||
|
||||
|
@ -42,6 +42,7 @@ struct DnsStream {
|
||||
|
||||
#if ENABLE_DNS_OVER_TLS
|
||||
DnsTlsStreamData dnstls_data;
|
||||
int dnstls_events;
|
||||
#endif
|
||||
|
||||
sd_event_source *io_event_source;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user