]> git.ipfire.org Git - thirdparty/systemd.git/commit - src/resolve/resolved-dnstls-gnutls.c
resolved: Fix DoT timeout on multiple answer records
authorJoan Bruguera <joanbrugueram@gmail.com>
Sat, 15 Jan 2022 16:33:25 +0000 (17:33 +0100)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 27 Jan 2022 05:33:28 +0000 (14:33 +0900)
commit2aaf6bb6e99b0f2bd73e0c49bef9e11a2844bf1a
tree9f35e9890af7dc3dd0f49c011b8222aa2f7405f9
parenta42a93830fcc18da073a5ac06f93c386efc9109d
resolved: Fix DoT timeout on multiple answer records

When sending multiple DNS questions to a DNS-over-TLS server (e.g. a question
for A and AAAA records, as is typical) on the same session, the server may
answer to each question in a separate TLS record, but it may also aggregate
multiple answers in a single TLS record.
(Some servers do this very often (e.g. Cloudflare 1.0.0.1), some do it sometimes
(e.g. Google 8.8.8.8) and some seem to never do it (e.g. Quad9 9.9.9.10)).

Both cases should be handled equivalently, as the byte stream is the same, but
when multiple answers came in a single TLS record, usually the first answer was
processed, but the second answer was entirely ignored, which caused a 10s delay
until the resolution timed out and the missing question was retried.
This can be reproduced by configuring one of the offending server and running
`resolvectl query google.com --cache=no` a few times.

To be notified of incoming data, systemd-resolved listens to `EPOLLIN` events
on the underlying socket. However, when DNS-over-TLS is used, the TLS library
(OpenSSL or GnuTLS) may read and buffer the entire TLS record when reading the
first answer, so usually no further `EPOLLIN` events will be generated, and the
second answer will never be processed.

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.
src/resolve/resolved-dns-stream.c
src/resolve/resolved-dnstls-gnutls.c
src/resolve/resolved-dnstls-openssl.c
src/resolve/resolved-dnstls.h