resolved: load libcrypto/libssl lazily on first use and make them optional (#42681)

Currently they are marked as required, as resolved aborts on startup if
dns-over-tls is built in, even if it is not enabled in the config.
Change initialization to be done lazily on first use, so that if the
config is not enabled, it never runs, and the libraries are never
dlopened, so they can be downgraded to recommends.
This commit is contained in:
Luca Boccassi
2026-06-22 14:15:39 +01:00
committed by GitHub
9 changed files with 61 additions and 26 deletions
+13
View File
@@ -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@.
+9
View File
@@ -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)
+3 -4
View File
@@ -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;
+13 -1
View File
@@ -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
+19 -7
View File
@@ -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;
}
-6
View File
@@ -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;
-8
View File
@@ -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);
+1
View File
@@ -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)
+3
View File
@@ -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