]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dnstls-openssl.c
resolved: Fix DoT timeout on multiple answer records
[thirdparty/systemd.git] / src / resolve / resolved-dnstls-openssl.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #if !ENABLE_DNS_OVER_TLS || !DNS_OVER_TLS_USE_OPENSSL
4 #error This source file requires DNS-over-TLS to be enabled and OpenSSL to be available.
5 #endif
6
7 #include <openssl/bio.h>
8 #include <openssl/err.h>
9 #include <openssl/x509v3.h>
10
11 #include "io-util.h"
12 #include "openssl-util.h"
13 #include "resolved-dns-stream.h"
14 #include "resolved-dnstls.h"
15 #include "resolved-manager.h"
16
17 static int dnstls_flush_write_buffer(DnsStream *stream) {
18 ssize_t ss;
19
20 assert(stream);
21 assert(stream->encrypted);
22
23 if (stream->dnstls_data.buffer_offset < stream->dnstls_data.write_buffer->length) {
24 assert(stream->dnstls_data.write_buffer->data);
25
26 struct iovec iov[1];
27 iov[0] = IOVEC_MAKE(stream->dnstls_data.write_buffer->data + stream->dnstls_data.buffer_offset,
28 stream->dnstls_data.write_buffer->length - stream->dnstls_data.buffer_offset);
29 ss = dns_stream_writev(stream, iov, 1, DNS_STREAM_WRITE_TLS_DATA);
30 if (ss < 0) {
31 if (ss == -EAGAIN)
32 stream->dnstls_events |= EPOLLOUT;
33
34 return ss;
35 } else {
36 stream->dnstls_data.buffer_offset += ss;
37
38 if (stream->dnstls_data.buffer_offset < stream->dnstls_data.write_buffer->length) {
39 stream->dnstls_events |= EPOLLOUT;
40 return -EAGAIN;
41 } else {
42 BIO_reset(SSL_get_wbio(stream->dnstls_data.ssl));
43 stream->dnstls_data.buffer_offset = 0;
44 }
45 }
46 }
47
48 return 0;
49 }
50
51 int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
52 _cleanup_(BIO_freep) BIO *rb = NULL, *wb = NULL;
53 _cleanup_(SSL_freep) SSL *s = NULL;
54 int error, r;
55
56 assert(stream);
57 assert(stream->manager);
58 assert(server);
59
60 rb = BIO_new_socket(stream->fd, 0);
61 if (!rb)
62 return -ENOMEM;
63
64 wb = BIO_new(BIO_s_mem());
65 if (!wb)
66 return -ENOMEM;
67
68 BIO_get_mem_ptr(wb, &stream->dnstls_data.write_buffer);
69 stream->dnstls_data.buffer_offset = 0;
70
71 s = SSL_new(stream->manager->dnstls_data.ctx);
72 if (!s)
73 return -ENOMEM;
74
75 SSL_set_connect_state(s);
76 r = SSL_set_session(s, server->dnstls_data.session);
77 if (r == 0)
78 return -EIO;
79 SSL_set_bio(s, TAKE_PTR(rb), TAKE_PTR(wb));
80
81 if (server->manager->dns_over_tls_mode == DNS_OVER_TLS_YES) {
82 X509_VERIFY_PARAM *v;
83
84 SSL_set_verify(s, SSL_VERIFY_PEER, NULL);
85 v = SSL_get0_param(s);
86 if (server->server_name) {
87 X509_VERIFY_PARAM_set_hostflags(v, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
88 if (X509_VERIFY_PARAM_set1_host(v, server->server_name, 0) == 0)
89 return -ECONNREFUSED;
90 } else {
91 const unsigned char *ip;
92 ip = server->family == AF_INET ? (const unsigned char*) &server->address.in.s_addr : server->address.in6.s6_addr;
93 if (X509_VERIFY_PARAM_set1_ip(v, ip, FAMILY_ADDRESS_SIZE(server->family)) == 0)
94 return -ECONNREFUSED;
95 }
96 }
97
98 if (server->server_name) {
99 r = SSL_set_tlsext_host_name(s, server->server_name);
100 if (r <= 0) {
101 char errbuf[256];
102
103 error = ERR_get_error();
104 ERR_error_string_n(error, errbuf, sizeof(errbuf));
105 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set server name: %s", errbuf);
106 }
107 }
108
109 ERR_clear_error();
110 stream->dnstls_data.handshake = SSL_do_handshake(s);
111 if (stream->dnstls_data.handshake <= 0) {
112 error = SSL_get_error(s, stream->dnstls_data.handshake);
113 if (!IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
114 char errbuf[256];
115
116 ERR_error_string_n(error, errbuf, sizeof(errbuf));
117 return log_debug_errno(SYNTHETIC_ERRNO(ECONNREFUSED),
118 "Failed to invoke SSL_do_handshake: %s", errbuf);
119 }
120 }
121
122 stream->encrypted = true;
123 stream->dnstls_data.ssl = TAKE_PTR(s);
124
125 r = dnstls_flush_write_buffer(stream);
126 if (r < 0 && r != -EAGAIN) {
127 SSL_free(TAKE_PTR(stream->dnstls_data.ssl));
128 return r;
129 }
130
131 return 0;
132 }
133
134 void dnstls_stream_free(DnsStream *stream) {
135 assert(stream);
136 assert(stream->encrypted);
137
138 if (stream->dnstls_data.ssl)
139 SSL_free(stream->dnstls_data.ssl);
140 }
141
142 int dnstls_stream_on_io(DnsStream *stream, uint32_t revents) {
143 int error, r;
144
145 assert(stream);
146 assert(stream->encrypted);
147 assert(stream->dnstls_data.ssl);
148
149 /* Flush write buffer when requested by OpenSSL */
150 if ((revents & EPOLLOUT) && (stream->dnstls_events & EPOLLOUT)) {
151 r = dnstls_flush_write_buffer(stream);
152 if (r < 0)
153 return r;
154 }
155
156 if (stream->dnstls_data.shutdown) {
157 ERR_clear_error();
158 r = SSL_shutdown(stream->dnstls_data.ssl);
159 if (r == 0) {
160 stream->dnstls_events = 0;
161
162 r = dnstls_flush_write_buffer(stream);
163 if (r < 0)
164 return r;
165
166 return -EAGAIN;
167 } else if (r < 0) {
168 error = SSL_get_error(stream->dnstls_data.ssl, r);
169 if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
170 stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
171
172 r = dnstls_flush_write_buffer(stream);
173 if (r < 0)
174 return r;
175
176 return -EAGAIN;
177 } else if (error == SSL_ERROR_SYSCALL) {
178 if (errno > 0)
179 log_debug_errno(errno, "Failed to invoke SSL_shutdown, ignoring: %m");
180 } else {
181 char errbuf[256];
182
183 ERR_error_string_n(error, errbuf, sizeof(errbuf));
184 log_debug("Failed to invoke SSL_shutdown, ignoring: %s", errbuf);
185 }
186 }
187
188 stream->dnstls_events = 0;
189 stream->dnstls_data.shutdown = false;
190
191 r = dnstls_flush_write_buffer(stream);
192 if (r < 0)
193 return r;
194
195 dns_stream_unref(stream);
196 return DNSTLS_STREAM_CLOSED;
197 } else if (stream->dnstls_data.handshake <= 0) {
198 ERR_clear_error();
199 stream->dnstls_data.handshake = SSL_do_handshake(stream->dnstls_data.ssl);
200 if (stream->dnstls_data.handshake <= 0) {
201 error = SSL_get_error(stream->dnstls_data.ssl, stream->dnstls_data.handshake);
202 if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
203 stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
204 r = dnstls_flush_write_buffer(stream);
205 if (r < 0)
206 return r;
207
208 return -EAGAIN;
209 } else {
210 char errbuf[256];
211
212 ERR_error_string_n(error, errbuf, sizeof(errbuf));
213 return log_debug_errno(SYNTHETIC_ERRNO(ECONNREFUSED),
214 "Failed to invoke SSL_do_handshake: %s",
215 errbuf);
216 }
217 }
218
219 stream->dnstls_events = 0;
220 r = dnstls_flush_write_buffer(stream);
221 if (r < 0)
222 return r;
223 }
224
225 return 0;
226 }
227
228 int dnstls_stream_shutdown(DnsStream *stream, int error) {
229 int ssl_error, r;
230 SSL_SESSION *s;
231
232 assert(stream);
233 assert(stream->encrypted);
234 assert(stream->dnstls_data.ssl);
235
236 if (stream->server) {
237 s = SSL_get1_session(stream->dnstls_data.ssl);
238 if (s) {
239 if (stream->server->dnstls_data.session)
240 SSL_SESSION_free(stream->server->dnstls_data.session);
241
242 stream->server->dnstls_data.session = s;
243 }
244 }
245
246 if (error == ETIMEDOUT) {
247 ERR_clear_error();
248 r = SSL_shutdown(stream->dnstls_data.ssl);
249 if (r == 0) {
250 if (!stream->dnstls_data.shutdown) {
251 stream->dnstls_data.shutdown = true;
252 dns_stream_ref(stream);
253 }
254
255 stream->dnstls_events = 0;
256
257 r = dnstls_flush_write_buffer(stream);
258 if (r < 0)
259 return r;
260
261 return -EAGAIN;
262 } else if (r < 0) {
263 ssl_error = SSL_get_error(stream->dnstls_data.ssl, r);
264 if (IN_SET(ssl_error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
265 stream->dnstls_events = ssl_error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
266 r = dnstls_flush_write_buffer(stream);
267 if (r < 0 && r != -EAGAIN)
268 return r;
269
270 if (!stream->dnstls_data.shutdown) {
271 stream->dnstls_data.shutdown = true;
272 dns_stream_ref(stream);
273 }
274 return -EAGAIN;
275 } else if (ssl_error == SSL_ERROR_SYSCALL) {
276 if (errno > 0)
277 log_debug_errno(errno, "Failed to invoke SSL_shutdown, ignoring: %m");
278 } else {
279 char errbuf[256];
280
281 ERR_error_string_n(ssl_error, errbuf, sizeof(errbuf));
282 log_debug("Failed to invoke SSL_shutdown, ignoring: %s", errbuf);
283 }
284 }
285
286 stream->dnstls_events = 0;
287 r = dnstls_flush_write_buffer(stream);
288 if (r < 0)
289 return r;
290 }
291
292 return 0;
293 }
294
295 ssize_t dnstls_stream_write(DnsStream *stream, const char *buf, size_t count) {
296 int error, r;
297 ssize_t ss;
298
299 assert(stream);
300 assert(stream->encrypted);
301 assert(stream->dnstls_data.ssl);
302 assert(buf);
303
304 ERR_clear_error();
305 ss = r = SSL_write(stream->dnstls_data.ssl, buf, count);
306 if (r <= 0) {
307 error = SSL_get_error(stream->dnstls_data.ssl, r);
308 if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
309 stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
310 ss = -EAGAIN;
311 } else if (error == SSL_ERROR_ZERO_RETURN) {
312 stream->dnstls_events = 0;
313 ss = 0;
314 } else {
315 char errbuf[256];
316
317 ERR_error_string_n(error, errbuf, sizeof(errbuf));
318 log_debug("Failed to invoke SSL_write: %s", errbuf);
319 stream->dnstls_events = 0;
320 ss = -EPIPE;
321 }
322 } else
323 stream->dnstls_events = 0;
324
325 r = dnstls_flush_write_buffer(stream);
326 if (r < 0)
327 return r;
328
329 return ss;
330 }
331
332 ssize_t dnstls_stream_read(DnsStream *stream, void *buf, size_t count) {
333 int error, r;
334 ssize_t ss;
335
336 assert(stream);
337 assert(stream->encrypted);
338 assert(stream->dnstls_data.ssl);
339 assert(buf);
340
341 ERR_clear_error();
342 ss = r = SSL_read(stream->dnstls_data.ssl, buf, count);
343 if (r <= 0) {
344 error = SSL_get_error(stream->dnstls_data.ssl, r);
345 if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
346 stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
347 ss = -EAGAIN;
348 } else if (error == SSL_ERROR_ZERO_RETURN) {
349 stream->dnstls_events = 0;
350 ss = 0;
351 } else {
352 char errbuf[256];
353
354 ERR_error_string_n(error, errbuf, sizeof(errbuf));
355 log_debug("Failed to invoke SSL_read: %s", errbuf);
356 stream->dnstls_events = 0;
357 ss = -EPIPE;
358 }
359 } else
360 stream->dnstls_events = 0;
361
362 /* flush write buffer in cache of renegotiation */
363 r = dnstls_flush_write_buffer(stream);
364 if (r < 0)
365 return r;
366
367 return ss;
368 }
369
370 bool dnstls_stream_has_buffered_data(DnsStream *stream) {
371 assert(stream);
372 assert(stream->encrypted);
373 assert(stream->dnstls_data.ssl);
374
375 return SSL_has_pending(stream->dnstls_data.ssl) > 0;
376 }
377
378 void dnstls_server_free(DnsServer *server) {
379 assert(server);
380
381 if (server->dnstls_data.session)
382 SSL_SESSION_free(server->dnstls_data.session);
383 }
384
385 int dnstls_manager_init(Manager *manager) {
386 int r;
387
388 assert(manager);
389
390 ERR_load_crypto_strings();
391 SSL_load_error_strings();
392
393 manager->dnstls_data.ctx = SSL_CTX_new(TLS_client_method());
394 if (!manager->dnstls_data.ctx)
395 return -ENOMEM;
396
397 r = SSL_CTX_set_min_proto_version(manager->dnstls_data.ctx, TLS1_2_VERSION);
398 if (r == 0)
399 return -EIO;
400
401 (void) SSL_CTX_set_options(manager->dnstls_data.ctx, SSL_OP_NO_COMPRESSION);
402
403 r = SSL_CTX_set_default_verify_paths(manager->dnstls_data.ctx);
404 if (r == 0)
405 return log_warning_errno(SYNTHETIC_ERRNO(EIO),
406 "Failed to load system trust store: %s",
407 ERR_error_string(ERR_get_error(), NULL));
408
409 return 0;
410 }
411
412 void dnstls_manager_free(Manager *manager) {
413 assert(manager);
414
415 if (manager->dnstls_data.ctx)
416 SSL_CTX_free(manager->dnstls_data.ctx);
417 }