diff --git a/catalog/systemd.catalog.in b/catalog/systemd.catalog.in index 30da7bd5aa..a4d286f955 100644 --- a/catalog/systemd.catalog.in +++ b/catalog/systemd.catalog.in @@ -1024,3 +1024,16 @@ Support: %SUPPORT_URL% The Trusted Platform Module's (TPM) NV index support is too limited to properly implement NV index backed additional PCRs. NvPCRs will not be allocated or initialized, and will not be available on the system. + +-- eac6d394c925493deac2ba99f3c2bb11 +Subject: An optional dependency for @FEATURE@ is not installed +Defined-By: systemd +Support: %SUPPORT_URL% + +The @FEATURE@ feature that was requested depends on an optional component that +is loaded at runtime (for example a shared library opened via dlopen(3)), but +that component is not installed on this system. + +As a result @FEATURE@ is unavailable, and is either skipped, disabled, or +degraded to a fallback mode. Refer to the accompanying log message for the +specific dependency that is missing, then install it to enable @FEATURE@. diff --git a/src/basic/log.h b/src/basic/log.h index cb4e8b5d0f..17c20f8cf0 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -273,6 +273,15 @@ int log_emergency_level(void); log_struct_iovec_internal(level, error, PROJECT_FILE, __LINE__, __func__, iovec, n_iovec) #define log_struct_iovec(level, iovec, n_iovec) log_struct_iovec_errno(level, 0, iovec, n_iovec) +/* Like log_struct(), but with log_once() semantics */ +#define log_struct_once(level, ...) \ + ({ \ + if (ONCE) \ + log_struct(level, __VA_ARGS__); \ + else if (LOG_PRI(level) != LOG_DEBUG) \ + log_struct(LOG_DEBUG, __VA_ARGS__); \ + }) + /* This modifies the buffer passed! */ #define log_dump(level, buffer) \ log_dump_internal(level, 0, PROJECT_FILE, __LINE__, __func__, buffer) diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index d987ee4fa4..36eb3595d5 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -12,7 +12,6 @@ #include "memory-util.h" #include "memstream-util.h" #include "resolved-dns-dnssec.h" -#include "resolved-util.h" #include "sort-util.h" #include "string-table.h" #include "string-util.h" @@ -717,7 +716,7 @@ int dnssec_verify_rrset( assert(dnskey); assert(result); - r = DLOPEN_LIBCRYPTO(LOG_DEBUG, DLOPEN_LIBCRYPTO_PRIORITY); + r = DLOPEN_LIBCRYPTO(LOG_WARNING, SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED); if (r < 0) return r; @@ -1074,7 +1073,7 @@ int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds, assert(dnskey); assert(ds); - r = DLOPEN_LIBCRYPTO(LOG_DEBUG, DLOPEN_LIBCRYPTO_PRIORITY); + r = DLOPEN_LIBCRYPTO(LOG_WARNING, SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED); if (r < 0) return r; @@ -1214,7 +1213,7 @@ int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) { assert(name); assert(ret); - r = DLOPEN_LIBCRYPTO(LOG_DEBUG, DLOPEN_LIBCRYPTO_PRIORITY); + r = DLOPEN_LIBCRYPTO(LOG_WARNING, SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED); if (r < 0) return r; diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index cbfe24ee7e..0bad4a512a 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -788,8 +788,20 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) { assert(t->server); r = dnstls_stream_connect_tls(s, t->server); - if (r < 0) + if (r < 0) { + /* If libcrypto is not available treat this like a TLS connection loss, so + * that opportunistic DNS-over-TLS downgrades to plaintext instead of + * re-selecting a TLS feature level and failing on every attempt. */ + if (r == -EOPNOTSUPP) { + log_struct_once(LOG_WARNING, + LOG_MESSAGE_ID(SD_MESSAGE_MISSING_DEPENDENCY_STR), + LOG_ITEM("FEATURE=DNS-over-TLS"), + LOG_MESSAGE("DNS-over-TLS has been requested but the required TLS libraries (libssl/libcrypto) are not installed.")); + dns_server_packet_lost(t->server, IPPROTO_TCP, t->current_feature_level); + return -ECONNREFUSED; + } return r; + } } #endif diff --git a/src/resolve/resolved-dnstls.c b/src/resolve/resolved-dnstls.c index 6f489ae3bd..6bcbdb5260 100644 --- a/src/resolve/resolved-dnstls.c +++ b/src/resolve/resolved-dnstls.c @@ -71,6 +71,10 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) { assert(stream->manager); assert(server); + r = dnstls_manager_init(stream->manager); + if (r < 0) + return r; + rb = sym_BIO_new_socket(stream->fd, 0); if (!rb) return -ENOMEM; @@ -398,31 +402,39 @@ void dnstls_server_free(DnsServer *server) { } int dnstls_manager_init(Manager *manager) { + _cleanup_(SSL_CTX_freep) SSL_CTX *ctx = NULL; int r; assert(manager); - r = DLOPEN_LIBCRYPTO(LOG_WARNING, SD_ELF_NOTE_DLOPEN_PRIORITY_REQUIRED); + /* Load libcrypto/libssl on first use, so that the dependencies can be optional. */ + + if (manager->dnstls_data.ctx) + return 0; + + r = DLOPEN_LIBCRYPTO(LOG_WARNING, SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED); if (r < 0) return r; - r = DLOPEN_LIBSSL(LOG_WARNING, SD_ELF_NOTE_DLOPEN_PRIORITY_REQUIRED); + r = DLOPEN_LIBSSL(LOG_WARNING, SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED); if (r < 0) return r; - manager->dnstls_data.ctx = sym_SSL_CTX_new(sym_TLS_client_method()); - if (!manager->dnstls_data.ctx) + ctx = sym_SSL_CTX_new(sym_TLS_client_method()); + if (!ctx) return log_openssl_errors(LOG_WARNING, "Failed to create SSL context"); - r = sym_SSL_CTX_set_min_proto_version(manager->dnstls_data.ctx, TLS1_2_VERSION); + r = sym_SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); if (r == 0) return log_openssl_errors(LOG_WARNING, "Failed to set protocol version on SSL context"); - (void) sym_SSL_CTX_set_options(manager->dnstls_data.ctx, SSL_OP_NO_COMPRESSION); + (void) sym_SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); - r = sym_SSL_CTX_set_default_verify_paths(manager->dnstls_data.ctx); + r = sym_SSL_CTX_set_default_verify_paths(ctx); if (r == 0) return log_openssl_errors(LOG_WARNING, "Failed to load system trust store"); + + manager->dnstls_data.ctx = TAKE_PTR(ctx); return 0; } diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 29a7046be3..faf539195b 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -754,12 +754,6 @@ int manager_new(Manager **ret) { if (r < 0) log_warning_errno(r, "Failed to parse configuration file, ignoring: %m"); -#if ENABLE_DNS_OVER_TLS - r = dnstls_manager_init(m); - if (r < 0) - return r; -#endif - r = sd_event_default(&m->event); if (r < 0) return r; diff --git a/src/resolve/resolved-util.h b/src/resolve/resolved-util.h index 9e84b44145..446b7c9f1b 100644 --- a/src/resolve/resolved-util.h +++ b/src/resolve/resolved-util.h @@ -1,12 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include "sd-dlopen.h" - -#if ENABLE_DNS_OVER_TLS -# define DLOPEN_LIBCRYPTO_PRIORITY SD_ELF_NOTE_DLOPEN_PRIORITY_REQUIRED -#else -# define DLOPEN_LIBCRYPTO_PRIORITY SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED -#endif - int resolve_system_hostname(char **full_hostname, char **first_label); diff --git a/src/shared/ssl-util.h b/src/shared/ssl-util.h index 77b5c049f9..857d4b5e17 100644 --- a/src/shared/ssl-util.h +++ b/src/shared/ssl-util.h @@ -55,6 +55,7 @@ extern DLSYM_PROTOTYPE(TLS_client_method); sym_SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MIN_PROTO_VERSION, (version), NULL) DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(SSL*, sym_SSL_free, SSL_freep, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(SSL_CTX*, sym_SSL_CTX_free, SSL_CTX_freep, NULL); #else #define DLOPEN_LIBSSL(log_level, priority) dlopen_libssl(log_level) diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h index 6aabe88196..bb6a17d9b6 100644 --- a/src/systemd/sd-messages.h +++ b/src/systemd/sd-messages.h @@ -312,6 +312,9 @@ _SD_BEGIN_DECLARATIONS; #define SD_MESSAGE_TPM_NVPCR_UNSUPPORTED SD_ID128_MAKE(8f,07,a5,b8,14,ca,47,62,b8,9f,cc,30,82,e4,8a,ed) #define SD_MESSAGE_TPM_NVPCR_UNSUPPORTED_STR SD_ID128_MAKE_STR(8f,07,a5,b8,14,ca,47,62,b8,9f,cc,30,82,e4,8a,ed) +#define SD_MESSAGE_MISSING_DEPENDENCY SD_ID128_MAKE(ea,c6,d3,94,c9,25,49,3d,ea,c2,ba,99,f3,c2,bb,11) +#define SD_MESSAGE_MISSING_DEPENDENCY_STR SD_ID128_MAKE_STR(ea,c6,d3,94,c9,25,49,3d,ea,c2,ba,99,f3,c2,bb,11) + _SD_END_DECLARATIONS; #endif