1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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.
7 #include <openssl/bio.h>
8 #include <openssl/err.h>
9 #include <openssl/x509v3.h>
12 #include "openssl-util.h"
13 #include "resolved-dns-stream.h"
14 #include "resolved-dnstls.h"
15 #include "resolved-manager.h"
17 static char *dnstls_error_string(int ssl_error
, char *buf
, size_t count
) {
18 assert(buf
|| count
== 0);
19 if (ssl_error
== SSL_ERROR_SSL
)
20 ERR_error_string_n(ERR_get_error(), buf
, count
);
22 snprintf(buf
, count
, "SSL_get_error()=%d", ssl_error
);
26 #define DNSTLS_ERROR_BUFSIZE 256
27 #define DNSTLS_ERROR_STRING(error) \
28 dnstls_error_string((error), (char[DNSTLS_ERROR_BUFSIZE]){}, DNSTLS_ERROR_BUFSIZE)
30 static int dnstls_flush_write_buffer(DnsStream
*stream
) {
34 assert(stream
->encrypted
);
36 if (stream
->dnstls_data
.buffer_offset
< stream
->dnstls_data
.write_buffer
->length
) {
37 assert(stream
->dnstls_data
.write_buffer
->data
);
40 iov
[0] = IOVEC_MAKE(stream
->dnstls_data
.write_buffer
->data
+ stream
->dnstls_data
.buffer_offset
,
41 stream
->dnstls_data
.write_buffer
->length
- stream
->dnstls_data
.buffer_offset
);
42 ss
= dns_stream_writev(stream
, iov
, 1, DNS_STREAM_WRITE_TLS_DATA
);
45 stream
->dnstls_events
|= EPOLLOUT
;
49 stream
->dnstls_data
.buffer_offset
+= ss
;
51 if (stream
->dnstls_data
.buffer_offset
< stream
->dnstls_data
.write_buffer
->length
) {
52 stream
->dnstls_events
|= EPOLLOUT
;
55 BIO_reset(SSL_get_wbio(stream
->dnstls_data
.ssl
));
56 stream
->dnstls_data
.buffer_offset
= 0;
64 int dnstls_stream_connect_tls(DnsStream
*stream
, DnsServer
*server
) {
65 _cleanup_(BIO_freep
) BIO
*rb
= NULL
, *wb
= NULL
;
66 _cleanup_(SSL_freep
) SSL
*s
= NULL
;
70 assert(stream
->manager
);
73 rb
= BIO_new_socket(stream
->fd
, 0);
77 wb
= BIO_new(BIO_s_mem());
81 BIO_get_mem_ptr(wb
, &stream
->dnstls_data
.write_buffer
);
82 stream
->dnstls_data
.buffer_offset
= 0;
84 s
= SSL_new(stream
->manager
->dnstls_data
.ctx
);
88 SSL_set_connect_state(s
);
89 r
= SSL_set_session(s
, server
->dnstls_data
.session
);
92 SSL_set_bio(s
, TAKE_PTR(rb
), TAKE_PTR(wb
));
94 if (server
->manager
->dns_over_tls_mode
== DNS_OVER_TLS_YES
) {
97 SSL_set_verify(s
, SSL_VERIFY_PEER
, NULL
);
98 v
= SSL_get0_param(s
);
99 if (server
->server_name
) {
100 X509_VERIFY_PARAM_set_hostflags(v
, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS
);
101 if (X509_VERIFY_PARAM_set1_host(v
, server
->server_name
, 0) == 0)
102 return -ECONNREFUSED
;
104 const unsigned char *ip
;
105 ip
= server
->family
== AF_INET
? (const unsigned char*) &server
->address
.in
.s_addr
: server
->address
.in6
.s6_addr
;
106 if (X509_VERIFY_PARAM_set1_ip(v
, ip
, FAMILY_ADDRESS_SIZE(server
->family
)) == 0)
107 return -ECONNREFUSED
;
111 if (server
->server_name
) {
112 r
= SSL_set_tlsext_host_name(s
, server
->server_name
);
114 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
115 "Failed to set server name: %s", DNSTLS_ERROR_STRING(SSL_ERROR_SSL
));
119 stream
->dnstls_data
.handshake
= SSL_do_handshake(s
);
120 if (stream
->dnstls_data
.handshake
<= 0) {
121 error
= SSL_get_error(s
, stream
->dnstls_data
.handshake
);
122 if (!IN_SET(error
, SSL_ERROR_WANT_READ
, SSL_ERROR_WANT_WRITE
))
123 return log_debug_errno(SYNTHETIC_ERRNO(ECONNREFUSED
),
124 "Failed to invoke SSL_do_handshake: %s", DNSTLS_ERROR_STRING(error
));
127 stream
->encrypted
= true;
128 stream
->dnstls_data
.ssl
= TAKE_PTR(s
);
130 r
= dnstls_flush_write_buffer(stream
);
131 if (r
< 0 && r
!= -EAGAIN
) {
132 SSL_free(TAKE_PTR(stream
->dnstls_data
.ssl
));
139 void dnstls_stream_free(DnsStream
*stream
) {
141 assert(stream
->encrypted
);
143 if (stream
->dnstls_data
.ssl
)
144 SSL_free(stream
->dnstls_data
.ssl
);
147 int dnstls_stream_on_io(DnsStream
*stream
, uint32_t revents
) {
151 assert(stream
->encrypted
);
152 assert(stream
->dnstls_data
.ssl
);
154 /* Flush write buffer when requested by OpenSSL */
155 if ((revents
& EPOLLOUT
) && (stream
->dnstls_events
& EPOLLOUT
)) {
156 r
= dnstls_flush_write_buffer(stream
);
161 if (stream
->dnstls_data
.shutdown
) {
163 r
= SSL_shutdown(stream
->dnstls_data
.ssl
);
165 stream
->dnstls_events
= 0;
167 r
= dnstls_flush_write_buffer(stream
);
173 error
= SSL_get_error(stream
->dnstls_data
.ssl
, r
);
174 if (IN_SET(error
, SSL_ERROR_WANT_READ
, SSL_ERROR_WANT_WRITE
)) {
175 stream
->dnstls_events
= error
== SSL_ERROR_WANT_READ
? EPOLLIN
: EPOLLOUT
;
177 r
= dnstls_flush_write_buffer(stream
);
182 } else if (error
== SSL_ERROR_SYSCALL
) {
184 log_debug_errno(errno
, "Failed to invoke SSL_shutdown, ignoring: %m");
186 log_debug("Failed to invoke SSL_shutdown, ignoring: %s", DNSTLS_ERROR_STRING(error
));
189 stream
->dnstls_events
= 0;
190 stream
->dnstls_data
.shutdown
= false;
192 r
= dnstls_flush_write_buffer(stream
);
196 dns_stream_unref(stream
);
197 return DNSTLS_STREAM_CLOSED
;
198 } else if (stream
->dnstls_data
.handshake
<= 0) {
200 stream
->dnstls_data
.handshake
= SSL_do_handshake(stream
->dnstls_data
.ssl
);
201 if (stream
->dnstls_data
.handshake
<= 0) {
202 error
= SSL_get_error(stream
->dnstls_data
.ssl
, stream
->dnstls_data
.handshake
);
203 if (IN_SET(error
, SSL_ERROR_WANT_READ
, SSL_ERROR_WANT_WRITE
)) {
204 stream
->dnstls_events
= error
== SSL_ERROR_WANT_READ
? EPOLLIN
: EPOLLOUT
;
205 r
= dnstls_flush_write_buffer(stream
);
211 return log_debug_errno(SYNTHETIC_ERRNO(ECONNREFUSED
),
212 "Failed to invoke SSL_do_handshake: %s",
213 DNSTLS_ERROR_STRING(error
));
216 stream
->dnstls_events
= 0;
217 r
= dnstls_flush_write_buffer(stream
);
225 int dnstls_stream_shutdown(DnsStream
*stream
, int error
) {
230 assert(stream
->encrypted
);
231 assert(stream
->dnstls_data
.ssl
);
233 if (stream
->server
) {
234 s
= SSL_get1_session(stream
->dnstls_data
.ssl
);
236 if (stream
->server
->dnstls_data
.session
)
237 SSL_SESSION_free(stream
->server
->dnstls_data
.session
);
239 stream
->server
->dnstls_data
.session
= s
;
243 if (error
== ETIMEDOUT
) {
245 r
= SSL_shutdown(stream
->dnstls_data
.ssl
);
247 if (!stream
->dnstls_data
.shutdown
) {
248 stream
->dnstls_data
.shutdown
= true;
249 dns_stream_ref(stream
);
252 stream
->dnstls_events
= 0;
254 r
= dnstls_flush_write_buffer(stream
);
260 ssl_error
= SSL_get_error(stream
->dnstls_data
.ssl
, r
);
261 if (IN_SET(ssl_error
, SSL_ERROR_WANT_READ
, SSL_ERROR_WANT_WRITE
)) {
262 stream
->dnstls_events
= ssl_error
== SSL_ERROR_WANT_READ
? EPOLLIN
: EPOLLOUT
;
263 r
= dnstls_flush_write_buffer(stream
);
264 if (r
< 0 && r
!= -EAGAIN
)
267 if (!stream
->dnstls_data
.shutdown
) {
268 stream
->dnstls_data
.shutdown
= true;
269 dns_stream_ref(stream
);
272 } else if (ssl_error
== SSL_ERROR_SYSCALL
) {
274 log_debug_errno(errno
, "Failed to invoke SSL_shutdown, ignoring: %m");
276 log_debug("Failed to invoke SSL_shutdown, ignoring: %s", DNSTLS_ERROR_STRING(ssl_error
));
279 stream
->dnstls_events
= 0;
280 r
= dnstls_flush_write_buffer(stream
);
288 static ssize_t
dnstls_stream_write(DnsStream
*stream
, const char *buf
, size_t count
) {
293 ss
= r
= SSL_write(stream
->dnstls_data
.ssl
, buf
, count
);
295 error
= SSL_get_error(stream
->dnstls_data
.ssl
, r
);
296 if (IN_SET(error
, SSL_ERROR_WANT_READ
, SSL_ERROR_WANT_WRITE
)) {
297 stream
->dnstls_events
= error
== SSL_ERROR_WANT_READ
? EPOLLIN
: EPOLLOUT
;
299 } else if (error
== SSL_ERROR_ZERO_RETURN
) {
300 stream
->dnstls_events
= 0;
303 log_debug("Failed to invoke SSL_write: %s", DNSTLS_ERROR_STRING(error
));
304 stream
->dnstls_events
= 0;
308 stream
->dnstls_events
= 0;
310 r
= dnstls_flush_write_buffer(stream
);
317 ssize_t
dnstls_stream_writev(DnsStream
*stream
, const struct iovec
*iov
, size_t iovcnt
) {
318 _cleanup_free_
char *buf
= NULL
;
322 assert(stream
->encrypted
);
323 assert(stream
->dnstls_data
.ssl
);
325 assert(iovec_total_size(iov
, iovcnt
) > 0);
328 return dnstls_stream_write(stream
, iov
[0].iov_base
, iov
[0].iov_len
);
330 /* As of now, OpenSSL cannot accumulate multiple writes, so join into a
331 single buffer. Suboptimal, but better than multiple SSL_write calls. */
332 count
= iovec_total_size(iov
, iovcnt
);
333 buf
= new(char, count
);
334 for (size_t i
= 0, pos
= 0; i
< iovcnt
; pos
+= iov
[i
].iov_len
, i
++)
335 memcpy(buf
+ pos
, iov
[i
].iov_base
, iov
[i
].iov_len
);
337 return dnstls_stream_write(stream
, buf
, count
);
340 ssize_t
dnstls_stream_read(DnsStream
*stream
, void *buf
, size_t count
) {
345 assert(stream
->encrypted
);
346 assert(stream
->dnstls_data
.ssl
);
350 ss
= r
= SSL_read(stream
->dnstls_data
.ssl
, buf
, count
);
352 error
= SSL_get_error(stream
->dnstls_data
.ssl
, r
);
353 if (IN_SET(error
, SSL_ERROR_WANT_READ
, SSL_ERROR_WANT_WRITE
)) {
354 /* If we receive SSL_ERROR_WANT_READ here, there are two possible scenarios:
355 * OpenSSL needs to renegotiate (so we want to get an EPOLLIN event), or
356 * There is no more application data is available, so we can just return
357 And apparently there's no nice way to distinguish between the two.
358 To handle this, never set EPOLLIN and just continue as usual.
359 If OpenSSL really wants to read due to renegotiation, it will tell us
360 again on SSL_write (at which point we will request EPOLLIN force a read);
361 or we will just eventually read data anyway while we wait for a packet */
362 stream
->dnstls_events
= error
== SSL_ERROR_WANT_READ
? 0 : EPOLLOUT
;
364 } else if (error
== SSL_ERROR_ZERO_RETURN
) {
365 stream
->dnstls_events
= 0;
368 log_debug("Failed to invoke SSL_read: %s", DNSTLS_ERROR_STRING(error
));
369 stream
->dnstls_events
= 0;
373 stream
->dnstls_events
= 0;
375 /* flush write buffer in cache of renegotiation */
376 r
= dnstls_flush_write_buffer(stream
);
383 void dnstls_server_free(DnsServer
*server
) {
386 if (server
->dnstls_data
.session
)
387 SSL_SESSION_free(server
->dnstls_data
.session
);
390 int dnstls_manager_init(Manager
*manager
) {
395 ERR_load_crypto_strings();
396 SSL_load_error_strings();
398 manager
->dnstls_data
.ctx
= SSL_CTX_new(TLS_client_method());
399 if (!manager
->dnstls_data
.ctx
)
402 r
= SSL_CTX_set_min_proto_version(manager
->dnstls_data
.ctx
, TLS1_2_VERSION
);
406 (void) SSL_CTX_set_options(manager
->dnstls_data
.ctx
, SSL_OP_NO_COMPRESSION
);
408 r
= SSL_CTX_set_default_verify_paths(manager
->dnstls_data
.ctx
);
410 return log_warning_errno(SYNTHETIC_ERRNO(EIO
),
411 "Failed to load system trust store: %s",
412 ERR_error_string(ERR_get_error(), NULL
));
417 void dnstls_manager_free(Manager
*manager
) {
420 if (manager
->dnstls_data
.ctx
)
421 SSL_CTX_free(manager
->dnstls_data
.ctx
);