]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dnstls-openssl.c
test: remove unnecessary include
[thirdparty/systemd.git] / src / resolve / resolved-dnstls-openssl.c
CommitLineData
096cbdce
IT
1/* SPDX-License-Identifier: LGPL-2.1+ */
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
096cbdce
IT
7#include <openssl/bio.h>
8#include <openssl/err.h>
9
72938b93
YW
10#include "resolved-dns-stream.h"
11#include "resolved-dnstls.h"
12
09e5c07f
AT
13#include "io-util.h"
14
096cbdce
IT
15DEFINE_TRIVIAL_CLEANUP_FUNC(SSL*, SSL_free);
16DEFINE_TRIVIAL_CLEANUP_FUNC(BIO*, BIO_free);
17
04c4d919
IT
18static int dnstls_flush_write_buffer(DnsStream *stream) {
19 ssize_t ss;
20
21 assert(stream);
22 assert(stream->encrypted);
23
24 if (stream->dnstls_data.write_buffer->length > 0) {
25 assert(stream->dnstls_data.write_buffer->data);
26
27 struct iovec iov[1];
5cfa2c3d
LP
28 iov[0] = IOVEC_MAKE(stream->dnstls_data.write_buffer->data,
29 stream->dnstls_data.write_buffer->length);
04c4d919
IT
30 ss = dns_stream_writev(stream, iov, 1, DNS_STREAM_WRITE_TLS_DATA);
31 if (ss < 0) {
32 if (ss == -EAGAIN)
33 stream->dnstls_events |= EPOLLOUT;
34
35 return ss;
36 } else {
37 stream->dnstls_data.write_buffer->length -= ss;
38 stream->dnstls_data.write_buffer->data += ss;
39
40 if (stream->dnstls_data.write_buffer->length > 0) {
41 stream->dnstls_events |= EPOLLOUT;
42 return -EAGAIN;
43 }
44 }
45 }
46
47 return 0;
48}
49
096cbdce 50int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
36f1946c 51 _cleanup_(BIO_freep) BIO *rb = NULL, *wb = NULL;
096cbdce 52 _cleanup_(SSL_freep) SSL *s = NULL;
36f1946c 53 int error, r;
096cbdce
IT
54
55 assert(stream);
56 assert(server);
57
04c4d919
IT
58 rb = BIO_new_socket(stream->fd, 0);
59 if (!rb)
60 return -ENOMEM;
61
62 wb = BIO_new(BIO_s_mem());
63 if (!wb)
096cbdce
IT
64 return -ENOMEM;
65
04c4d919
IT
66 BIO_get_mem_ptr(wb, &stream->dnstls_data.write_buffer);
67
096cbdce
IT
68 s = SSL_new(server->dnstls_data.ctx);
69 if (!s)
70 return -ENOMEM;
71
72 SSL_set_connect_state(s);
04c4d919
IT
73 SSL_set_session(s, server->dnstls_data.session);
74 SSL_set_bio(s, TAKE_PTR(rb), TAKE_PTR(wb));
75
59c3fee2 76 ERR_clear_error();
04c4d919
IT
77 stream->dnstls_data.handshake = SSL_do_handshake(s);
78 if (stream->dnstls_data.handshake <= 0) {
79 error = SSL_get_error(s, stream->dnstls_data.handshake);
80 if (!IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
81 char errbuf[256];
096cbdce 82
04c4d919
IT
83 ERR_error_string_n(error, errbuf, sizeof(errbuf));
84 log_debug("Failed to invoke SSL_do_handshake: %s", errbuf);
85 return -ECONNREFUSED;
86 }
87 }
096cbdce
IT
88
89 stream->encrypted = true;
04c4d919
IT
90
91 r = dnstls_flush_write_buffer(stream);
92 if (r < 0 && r != -EAGAIN)
93 return r;
94
096cbdce
IT
95 stream->dnstls_data.ssl = TAKE_PTR(s);
96
97 return 0;
98}
99
100void dnstls_stream_free(DnsStream *stream) {
101 assert(stream);
102 assert(stream->encrypted);
103
104 if (stream->dnstls_data.ssl)
105 SSL_free(stream->dnstls_data.ssl);
106}
107
04c4d919 108int dnstls_stream_on_io(DnsStream *stream, uint32_t revents) {
36f1946c 109 int error, r;
096cbdce
IT
110
111 assert(stream);
112 assert(stream->encrypted);
113 assert(stream->dnstls_data.ssl);
114
36f1946c 115 /* Flush write buffer when requested by OpenSSL */
04c4d919
IT
116 if ((revents & EPOLLOUT) && (stream->dnstls_events & EPOLLOUT)) {
117 r = dnstls_flush_write_buffer(stream);
118 if (r < 0)
119 return r;
120 }
121
096cbdce 122 if (stream->dnstls_data.shutdown) {
59c3fee2 123 ERR_clear_error();
096cbdce 124 r = SSL_shutdown(stream->dnstls_data.ssl);
8eadd291
YW
125 if (r == 0) {
126 stream->dnstls_events = 0;
127
128 r = dnstls_flush_write_buffer(stream);
129 if (r < 0)
130 return r;
131
132 return -EAGAIN;
133 } else if (r < 0) {
096cbdce 134 error = SSL_get_error(stream->dnstls_data.ssl, r);
8eadd291
YW
135 if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
136 stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
04c4d919
IT
137
138 r = dnstls_flush_write_buffer(stream);
139 if (r < 0)
140 return r;
141
096cbdce 142 return -EAGAIN;
8eadd291
YW
143 } else if (error == SSL_ERROR_SYSCALL) {
144 if (errno > 0)
145 log_debug_errno(errno, "Failed to invoke SSL_shutdown, ignoring: %m");
096cbdce
IT
146 } else {
147 char errbuf[256];
148
149 ERR_error_string_n(error, errbuf, sizeof(errbuf));
8eadd291 150 log_debug("Failed to invoke SSL_shutdown, ignoring: %s", errbuf);
096cbdce
IT
151 }
152 }
153
8eadd291
YW
154 stream->dnstls_events = 0;
155 stream->dnstls_data.shutdown = false;
156
04c4d919
IT
157 r = dnstls_flush_write_buffer(stream);
158 if (r < 0)
159 return r;
160
096cbdce
IT
161 dns_stream_unref(stream);
162 return DNSTLS_STREAM_CLOSED;
163 } else if (stream->dnstls_data.handshake <= 0) {
59c3fee2 164 ERR_clear_error();
096cbdce
IT
165 stream->dnstls_data.handshake = SSL_do_handshake(stream->dnstls_data.ssl);
166 if (stream->dnstls_data.handshake <= 0) {
167 error = SSL_get_error(stream->dnstls_data.ssl, stream->dnstls_data.handshake);
168 if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
169 stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
04c4d919
IT
170 r = dnstls_flush_write_buffer(stream);
171 if (r < 0)
172 return r;
173
096cbdce
IT
174 return -EAGAIN;
175 } else {
176 char errbuf[256];
177
178 ERR_error_string_n(error, errbuf, sizeof(errbuf));
baaa35ad
ZJS
179 return log_debug_errno(SYNTHETIC_ERRNO(ECONNREFUSED),
180 "Failed to invoke SSL_do_handshake: %s",
181 errbuf);
096cbdce
IT
182 }
183 }
184
185 stream->dnstls_events = 0;
04c4d919
IT
186 r = dnstls_flush_write_buffer(stream);
187 if (r < 0)
188 return r;
096cbdce
IT
189 }
190
191 return 0;
192}
193
194int dnstls_stream_shutdown(DnsStream *stream, int error) {
36f1946c 195 int ssl_error, r;
096cbdce
IT
196 SSL_SESSION *s;
197
198 assert(stream);
199 assert(stream->encrypted);
200 assert(stream->dnstls_data.ssl);
201
04c4d919
IT
202 if (stream->server) {
203 s = SSL_get1_session(stream->dnstls_data.ssl);
204 if (s) {
205 if (stream->server->dnstls_data.session)
206 SSL_SESSION_free(stream->server->dnstls_data.session);
207
208 stream->server->dnstls_data.session = s;
209 }
210 }
211
096cbdce 212 if (error == ETIMEDOUT) {
59c3fee2 213 ERR_clear_error();
096cbdce
IT
214 r = SSL_shutdown(stream->dnstls_data.ssl);
215 if (r == 0) {
216 if (!stream->dnstls_data.shutdown) {
217 stream->dnstls_data.shutdown = true;
218 dns_stream_ref(stream);
219 }
04c4d919 220
8eadd291
YW
221 stream->dnstls_events = 0;
222
04c4d919
IT
223 r = dnstls_flush_write_buffer(stream);
224 if (r < 0)
225 return r;
226
096cbdce
IT
227 return -EAGAIN;
228 } else if (r < 0) {
229 ssl_error = SSL_get_error(stream->dnstls_data.ssl, r);
230 if (IN_SET(ssl_error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
231 stream->dnstls_events = ssl_error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
04c4d919
IT
232 r = dnstls_flush_write_buffer(stream);
233 if (r < 0 && r != -EAGAIN)
234 return r;
235
096cbdce
IT
236 if (!stream->dnstls_data.shutdown) {
237 stream->dnstls_data.shutdown = true;
238 dns_stream_ref(stream);
239 }
240 return -EAGAIN;
8eadd291
YW
241 } else if (ssl_error == SSL_ERROR_SYSCALL) {
242 if (errno > 0)
243 log_debug_errno(errno, "Failed to invoke SSL_shutdown, ignoring: %m");
096cbdce
IT
244 } else {
245 char errbuf[256];
246
247 ERR_error_string_n(ssl_error, errbuf, sizeof(errbuf));
8eadd291 248 log_debug("Failed to invoke SSL_shutdown, ignoring: %s", errbuf);
096cbdce
IT
249 }
250 }
04c4d919
IT
251
252 stream->dnstls_events = 0;
253 r = dnstls_flush_write_buffer(stream);
254 if (r < 0)
255 return r;
096cbdce
IT
256 }
257
258 return 0;
259}
260
261ssize_t dnstls_stream_write(DnsStream *stream, const char *buf, size_t count) {
36f1946c 262 int error, r;
096cbdce
IT
263 ssize_t ss;
264
265 assert(stream);
266 assert(stream->encrypted);
267 assert(stream->dnstls_data.ssl);
268 assert(buf);
269
59c3fee2 270 ERR_clear_error();
096cbdce
IT
271 ss = r = SSL_write(stream->dnstls_data.ssl, buf, count);
272 if (r <= 0) {
8e740110 273 error = SSL_get_error(stream->dnstls_data.ssl, r);
096cbdce
IT
274 if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
275 stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
276 ss = -EAGAIN;
8e740110
YW
277 } else if (error == SSL_ERROR_ZERO_RETURN) {
278 stream->dnstls_events = 0;
279 ss = 0;
096cbdce
IT
280 } else {
281 char errbuf[256];
282
283 ERR_error_string_n(error, errbuf, sizeof(errbuf));
36f1946c 284 log_debug("Failed to invoke SSL_write: %s", errbuf);
8e740110 285 stream->dnstls_events = 0;
096cbdce
IT
286 ss = -EPIPE;
287 }
8e740110
YW
288 } else
289 stream->dnstls_events = 0;
096cbdce 290
04c4d919
IT
291 r = dnstls_flush_write_buffer(stream);
292 if (r < 0)
293 return r;
294
096cbdce
IT
295 return ss;
296}
297
298ssize_t dnstls_stream_read(DnsStream *stream, void *buf, size_t count) {
36f1946c 299 int error, r;
096cbdce
IT
300 ssize_t ss;
301
302 assert(stream);
303 assert(stream->encrypted);
304 assert(stream->dnstls_data.ssl);
305 assert(buf);
306
59c3fee2 307 ERR_clear_error();
096cbdce
IT
308 ss = r = SSL_read(stream->dnstls_data.ssl, buf, count);
309 if (r <= 0) {
8e740110 310 error = SSL_get_error(stream->dnstls_data.ssl, r);
096cbdce
IT
311 if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
312 stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
313 ss = -EAGAIN;
8e740110
YW
314 } else if (error == SSL_ERROR_ZERO_RETURN) {
315 stream->dnstls_events = 0;
316 ss = 0;
096cbdce
IT
317 } else {
318 char errbuf[256];
319
320 ERR_error_string_n(error, errbuf, sizeof(errbuf));
321 log_debug("Failed to invoke SSL_read: %s", errbuf);
8e740110 322 stream->dnstls_events = 0;
096cbdce
IT
323 ss = -EPIPE;
324 }
8e740110
YW
325 } else
326 stream->dnstls_events = 0;
04c4d919
IT
327
328 /* flush write buffer in cache of renegotiation */
329 r = dnstls_flush_write_buffer(stream);
330 if (r < 0)
331 return r;
332
096cbdce
IT
333 return ss;
334}
335
336void dnstls_server_init(DnsServer *server) {
337 assert(server);
338
339 server->dnstls_data.ctx = SSL_CTX_new(TLS_client_method());
340 if (server->dnstls_data.ctx) {
341 SSL_CTX_set_min_proto_version(server->dnstls_data.ctx, TLS1_2_VERSION);
342 SSL_CTX_set_options(server->dnstls_data.ctx, SSL_OP_NO_COMPRESSION);
343 }
344}
345
346void dnstls_server_free(DnsServer *server) {
347 assert(server);
348
349 if (server->dnstls_data.ctx)
350 SSL_CTX_free(server->dnstls_data.ctx);
04c4d919
IT
351
352 if (server->dnstls_data.session)
353 SSL_SESSION_free(server->dnstls_data.session);
096cbdce 354}