summaryrefslogtreecommitdiffstats
path: root/src/resolve/resolved-dns-stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/resolve/resolved-dns-stream.c')
-rw-r--r--src/resolve/resolved-dns-stream.c45
1 files changed, 43 insertions, 2 deletions
diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c
index f48e2a8029..51ffa6b4b0 100644
--- a/src/resolve/resolved-dns-stream.c
+++ b/src/resolve/resolved-dns-stream.c
@@ -6,6 +6,7 @@
#include "alloc-util.h"
#include "fd-util.h"
#include "io-util.h"
+#include "macro.h"
#include "missing_network.h"
#include "resolved-dns-stream.h"
#include "resolved-manager.h"
@@ -280,13 +281,15 @@ static int on_stream_timeout(sd_event_source *es, usec_t usec, void *userdata) {
return dns_stream_complete(s, ETIMEDOUT);
}
-static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
- _cleanup_(dns_stream_unrefp) DnsStream *s = dns_stream_ref(userdata); /* Protect stream while we process it */
+static int on_stream_io_impl(DnsStream *s, uint32_t revents) {
bool progressed = false;
int r;
assert(s);
+ /* This returns 1 when possible remaining stream exists, 0 on completed
+ stream or recoverable error, and negative errno on failure. */
+
#if ENABLE_DNS_OVER_TLS
if (s->encrypted) {
r = dnstls_stream_on_io(s, revents);
@@ -441,6 +444,44 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
log_warning_errno(errno, "Couldn't restart TCP connection timeout, ignoring: %m");
}
+ return 1;
+}
+
+static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
+ _cleanup_(dns_stream_unrefp) DnsStream *s = dns_stream_ref(userdata); /* Protect stream while we process it */
+ int r;
+
+ assert(s);
+
+ r = on_stream_io_impl(s, revents);
+ if (r <= 0)
+ return r;
+
+#if ENABLE_DNS_OVER_TLS
+ if (!s->encrypted)
+ return 0;
+
+ /* When using DNS-over-TLS, the underlying TLS library may read the entire TLS record
+ and buffer it internally. If this happens, we will not receive further EPOLLIN events,
+ and unless there's some unrelated activity on the socket, we will hang until time out.
+ To avoid this, if there's buffered TLS data, generate a "fake" EPOLLIN event.
+ This is hacky, but it makes this case transparent to the rest of the IO code. */
+ while (dnstls_stream_has_buffered_data(s)) {
+ uint32_t events;
+
+ /* Make sure the stream still wants to process more data... */
+ r = sd_event_source_get_io_events(s->io_event_source, &events);
+ if (r < 0)
+ return r;
+ if (!FLAGS_SET(events, EPOLLIN))
+ break;
+
+ r = on_stream_io_impl(s, EPOLLIN);
+ if (r <= 0)
+ return r;
+ }
+#endif
+
return 0;
}