diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-01-28 09:29:59 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-03-18 02:36:10 +0900 |
commit | 9c710c66c383adf2aa06e8c32bac5c100cf0fd8c (patch) | |
tree | 63f8eb679be5106f9edd26509c19a557f9716b22 | |
parent | d65808ef7e0fe558923336a8533df37ecb50dbfc (diff) | |
download | systemd-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.c | 22 | ||||
-rw-r--r-- | src/resolve/resolved-dns-stream.h | 1 | ||||
-rw-r--r-- | src/resolve/resolved-llmnr.c | 4 |
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) { |