summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2022-01-28 09:29:59 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-03-18 02:36:10 +0900
commit9c710c66c383adf2aa06e8c32bac5c100cf0fd8c (patch)
tree63f8eb679be5106f9edd26509c19a557f9716b22
parentd65808ef7e0fe558923336a8533df37ecb50dbfc (diff)
downloadsystemd-9c710c66c383adf2aa06e8c32bac5c100cf0fd8c.tar.gz
resolve: llmnr: fix never hit condition
Previously, the condition in on_stream_io_impl() never hit, as the read packet is always taken from the stream in the few lines above. Instead of the dns_stream_complete() under the condition, the stream is unref()ed in the on_packet callback for LLMNR stream, unlike the other on_packet callbacks. That's quite tricky. Also, potentially, the stream may still have queued packets to write. This fix the condition, and drops the unref() in the on_packet callback. C.f. https://github.com/systemd/systemd/pull/22274#issuecomment-1023708449. Closes #22266. (cherry picked from commit a5e2a488e83fabf6d8ade7621c2fc3574a8faaa7)
-rw-r--r--src/resolve/resolved-dns-stream.c22
-rw-r--r--src/resolve/resolved-dns-stream.h1
-rw-r--r--src/resolve/resolved-llmnr.c4
3 files changed, 17 insertions, 10 deletions
diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c
index d16ea95d43..cf9d1a9d5e 100644
--- a/src/resolve/resolved-dns-stream.c
+++ b/src/resolve/resolved-dns-stream.c
@@ -446,17 +446,25 @@ static int on_stream_io_impl(DnsStream *s, uint32_t revents) {
r = dns_stream_update_io(s);
if (r < 0)
return dns_stream_complete(s, -r);
+
+ s->packet_received = true;
}
}
}
- /* Call "complete" callback if finished reading and writing one packet, and there's nothing else left
- * to write. */
- if (s->type == DNS_STREAM_LLMNR_SEND &&
- (s->write_packet && s->n_written >= sizeof(s->write_size) + s->write_packet->size) &&
- ordered_set_isempty(s->write_queue) &&
- (s->read_packet && s->n_read >= sizeof(s->read_size) + s->read_packet->size))
- return dns_stream_complete(s, 0);
+ if (s->type == DNS_STREAM_LLMNR_SEND && s->packet_received) {
+ uint32_t events;
+
+ /* Complete the stream if finished reading and writing one packet, and there's nothing
+ * else left to write. */
+
+ r = sd_event_source_get_io_events(s->io_event_source, &events);
+ if (r < 0)
+ return r;
+
+ if (!FLAGS_SET(events, EPOLLOUT))
+ return dns_stream_complete(s, 0);
+ }
/* If we did something, let's restart the timeout event source */
if (progressed && s->timeout_event_source) {
diff --git a/src/resolve/resolved-dns-stream.h b/src/resolve/resolved-dns-stream.h
index fedbab2da2..1c606365cd 100644
--- a/src/resolve/resolved-dns-stream.h
+++ b/src/resolve/resolved-dns-stream.h
@@ -60,6 +60,7 @@ struct DnsStream {
int ifindex;
uint32_t ttl;
bool identified;
+ bool packet_received; /* At least one packet is received. Used by LLMNR. */
/* only when using TCP fast open */
union sockaddr_union tfo_address;
diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c
index b4e551c219..76e42940f4 100644
--- a/src/resolve/resolved-llmnr.c
+++ b/src/resolve/resolved-llmnr.c
@@ -294,7 +294,6 @@ static int on_llmnr_stream_packet(DnsStream *s, DnsPacket *p) {
} else
log_debug("Invalid LLMNR TCP packet, ignoring.");
- dns_stream_unref(s);
return 0;
}
@@ -311,8 +310,7 @@ static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *u
return -errno;
}
- /* We don't configure a "complete" handler here, we rely on the default handler than simply drops the
- * reference to the stream, thus freeing it */
+ /* We don't configure a "complete" handler here, we rely on the default handler, thus freeing it */
r = dns_stream_new(m, &stream, DNS_STREAM_LLMNR_RECV, DNS_PROTOCOL_LLMNR, cfd, NULL,
on_llmnr_stream_packet, NULL, DNS_STREAM_DEFAULT_TIMEOUT_USEC);
if (r < 0) {