The FlushCaches and ResetServerFeatures D-Bus methods perform
destructive operations (flushing all DNS caches and resetting server
feature negotiation including DNS-over-TLS state) without any
authorization check. The corresponding Varlink methods already enforce
polkit via verify_polkit(), but the D-Bus handlers were not updated.
Add bus_verify_polkit_async() calls to both methods, matching the
pattern used by ResetStatistics. Add the corresponding policy actions
to the polkit policy file.
Our baseline glibc is 2.34, which merged libdl, libpthread (the
dependency('threads') target), and librt into libc. Empty .so/.a stubs
remain for backward compatibility with old binaries, but new builds
resolve dl_*, pthread_*, mq_*, timer_*, etc. directly from libc.
On musl the same libraries are likewise empty stubs.
Drop the libdl, threads, and librt entries from every meson.build, and
remove the now-stale 'Libs.private: -lrt -pthread' from libudev.pc.in
since both flags resolve to empty link-time stubs on glibc 2.34+ and
musl.
Verified with readelf -d that libsystemd.so, libudev.so, and systemd no
longer carry DT_NEEDED entries for libdl/libpthread/librt.
Add CacheSize= option to [Resolve] section of resolved.conf to allow
configuring the maximum number of entries in the per-scope DNS cache.
The default remains 4096 entries. Setting this to 0 disables caching
(similar to Cache=no).
CacheSize= is only read when Cache=yes or Cache=no-negative. When
Cache=no, caching is fully disabled regardless of CacheSize=.
Changes:
- Add cache_size field to Manager struct
- Parse CacheSize= from resolved.conf via gperf
- Thread cache_size through dns_cache_put() and helper functions
- Replace hard-coded CACHE_MAX with the configurable cache_size
- When cache_size is 0 or Cache=no, flush cache and skip caching
- Add man page documentation for the new option
- Add unit tests for cache size enforcement
Co-developed-by: Claude <claude@anthropic.com>
Use the "resolvconf" namespace to keep these options separate from the
resolvectl/systemd-resolve sets.
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
Use OPTION_NAMESPACE() to keep the resolvectl and systemd-resolve
option sets separate. The resolvconf-compat path (resolvconf
invocation) keeps its own getopt-based parsing.
--help output has the expected changes to formatting. Synopis
for [status] is now shows that the verb is optional.
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
The search domain limit is already enforced by dns_search_domain_new(),
but in this case it's way too late. Let's enforce it during the first
loop to avoid unnecessary parsing.
Until now OpenSSL was linked into every binary and library that needed
cryptography, pulling libcrypto (and, for resolved, libssl) into the
address space of services that never touch them at runtime. This commit
moves all OpenSSL usage behind the same dlopen helper pattern that we
already use for other optional libraries (libpam, libseccomp, libxz, …)
so libcrypto/libssl are only loaded on demand.
The bulk of the work lives in src/shared/crypto-util.{c,h} (libcrypto)
and src/shared/ssl-util.{c,h} (libssl), which replace the previous
src/shared/openssl-util.{c,h}:
- crypto-util.{c,h} declares every libcrypto function we call via
DLSYM_PROTOTYPE() and resolves them inside dlopen_libcrypto().
- ssl-util.{c,h} holds the libssl-specific DLSYM_PROTOTYPEs,
dlopen_libssl(), and the SSL_freep cleanup helper, so translation
units that only need libcrypto do not pull in libssl declarations.
- Callers refer to the symbols through sym_* aliases rather than the
original names.
- Convenience macros that used to be provided by the OpenSSL headers
(OPENSSL_free, BN_num_bytes, the sk_TYPE_* helpers, …) are
reimplemented as sym_* wrappers so no code path needs to fall back
to the linker-resolved symbols.
- All _cleanup_ helpers are redefined in terms of the sym_* variants
(EVP_PKEY_freep, X509_freep, BIO_freep, …) so cleanup attributes
keep working without pulling in libcrypto symbols at link time.
- The public crypto-util.c entry points (openssl_pubkey_from_pem,
openssl_digest_many, openssl_hmac_many, openssl_cipher_many,
kdf_ss_derive, kdf_kb_hmac_derive, rsa_* / ecc_* helpers,
pubkey_fingerprint, digest_and_sign, pkcs7_new, x509_fingerprint,
openssl_extract_public_key, pkey_generate_volume_keys, the load_*
helpers, …) now call dlopen_libcrypto() at entry before touching any
sym_* pointer.
The call sites across the tree have been converted to call
dlopen_libcrypto()/dlopen_libssl() at the appropriate entry point
before their first sym_* use, and to use sym_* variants throughout:
- bootctl, sbsign, measure, pcrlock, pcrextend, tpm2-setup, repart,
cryptsetup, cryptenroll, homectl, homed, homework, keyutil,
sysupdate, creds, import, dissect-image, pe-binary, pkcs11-util,
pkcs7-util, tpm2-util, creds-util. resolved additionally dlopens
libssl for DoT.
The meson build files are updated to depend on libopenssl_cflags (a
new partial dependency that exposes include paths and compile flags
only, not the linker flags) instead of libopenssl for every target that
previously linked against OpenSSL. Nothing links against libcrypto or
libssl directly anymore.
A new src/sbsign/authenticode.c hosts the Authenticode ASN.1 type
definitions that used to live inline in sbsign.c. The OpenSSL
ASN1_SEQUENCE / ASN1_CHOICE / IMPLEMENT_ASN1_FUNCTIONS macros expand to
code that references libcrypto symbols directly, so to keep this
translation unit unlinked from libcrypto we redirect ASN1_item_* to
the sym_* variants via #define and wrap the ASN1_*_it() getters (which
appear as constant function pointers in static initializers) in small
trampoline functions that forward to the sym_* pointers at runtime.
test-dlopen-so gains assertions for dlopen_libcrypto and dlopen_libssl
so the dlopen contract is exercised in CI, and the openssl-specific
test was renamed from test-openssl.c to test-crypto-util.c to match
the new header naming.
This reverts commit 526f1594daec073269c3e70ee7914f6dd8740d5c.
This revert is necessary because the change breaks mDNS hostname stability
whenever a DNS-SD service calls UnregisterService. When a service
unregisters (e.g. on process restart), manager_refresh_rrs() clears and
re-adds all RRs in PROBING state, which sends a multicast announcement
(QR=1). The kernel reflects this back to resolved's own socket. Because
the local-address check was moved inside the query-only branch by the
reverted commit, the reply path in on_mdns_packet() is now unguarded.
The looped-back announcement matches the pending probe transaction and
completes it with DNS_TRANSACTION_SUCCESS. Since the zone item is still
in PROBING state (not ESTABLISHED), dns_zone_item_notify() sets
we_lost=true and calls dns_zone_item_conflict(), which invokes
manager_next_hostname() and renames the hostname (e.g. foo.local →
foo4.local). This happens reliably on every restart of any service using
RegisterService/UnregisterService (homebridge, avahi-compat wrappers,
etc.).
The top-level local-address check in on_mdns_packet() suppresses all
looped-back multicast traffic before the reply/query split. Restoring it
there is consistent with the overall design: dns_scope_check_conflicts()
already has its own manager_packet_from_local_address() guard and is
unaffected.
A more targeted long-term fix (e.g. guarding dns_transaction_process_reply()
for mDNS, or avoiding unnecessary re-probing of already-established records
in manager_refresh_rrs()) can be pursued separately.
Every dlopen_xxx() helper now takes an int log_level argument. It is
passed through to dlopen_many_sym_or_warn() (which in turn propagates it
to dlopen_verbose() for the library-not-installed case), and is used by
the fallback stub when support for the library is not compiled in to
emit a "<lib> support is not compiled in." message at the caller's level.
Callers pass LOG_DEBUG when gracefully degrading, or a higher level when
the failure should surface, and no longer need to log redundantly at the
call site.
As part of this, dlopen_bpf_full() (which already took a log_level) is
merged into dlopen_bpf() rather than keeping both.
The static inline fallbacks used to live in the headers, which required
pulling log.h in from every header that declared a dlopen_xxx(). Move
them into the .c files instead: the declaration is always outside the
#if HAVE_XXX block, the impl sits outside the outer #if HAVE_XXX wrap
with its own internal #if HAVE_XXX/#else/#endif, and apparmor-util.c,
idn-util.c, libmount-util.c and pam-util.c are now always compiled so
they can host their stubs.
The updated parsing_hacks.h file uncovered a bunch of extra
things that the check-pointer-deref coccinelle script flags.
This commit fixes them to make the tree check-pointer-deref clean.
As mentioned in the grandfather commit, I want to use the _many
suffix for freeing of the contents of an array, so the functions
to free the array to get the suffix _array.
dnssec_rsa_verify_raw() asserts that RSA_size(key) matches the RRSIG
signature size, and dnssec_ecdsa_verify_raw() asserts that
EC_KEY_check_key() succeeds. Both conditions depend on parsed DNS
record content. Replace with proper error returns.
The actual crypto verify calls (EVP_PKEY_verify / ECDSA_do_verify)
handle mismatches fine on their own, so the asserts were also redundant.
While at it, fix the misleading "EC_POINT_bn2point failed" log message
that actually refers to an EC_KEY_set_public_key() failure.
Fixes: https://github.com/systemd/systemd/issues/41569
manager_set_dns_server() and dns_server_flush_cache() call dns_cache_flush()
unconditionally, wiping the entire cache even when StaleRetentionSec is
configured. This defeats serve-stale by discarding cached records that should
remain available during server switches and feature-level re-probes.
The original serve-stale commit (5ed91481ab) added a stale_retention_usec
guard to link_set_dns_server(), and a later commit (7928c0e0a1) added the
same guard to dns_delegate_set_dns_server(), but these two call sites in
resolved-dns-server.c were missed.
This is particularly visible with DNSOverTLS, where TLS handshake failures
trigger frequent feature-level downgrades and re-probes via
dns_server_flush_cache(), flushing the cache each time.
Add the same stale_retention_usec guard to both call sites so that cache
entries are allowed to expire naturally via dns_cache_prune() when
serve-stale is enabled.
Fixes: #40781
This commit was prepared with assistance from an AI coding agent (GitHub
Copilot). All changes have been reviewed for correctness and adherence to the
systemd coding style.
We generally want to print an error message if table_print()
fails. Add a helper function for this and use it consistently.
This does one of the three things depending on the call site:
- a no-change reformatting of the code
- change from a custom message to the generic one
- addition of the error message where previously none was printed
In the third case, the actual use impact is very small, since the
table formatting is very unlikely to fail. But if it did, we would
often return an error without any message whatsoever, which we
never want to do.
Almost all callers of table_print() specify stdout or NULL (equivalent
to stdout) as the output stream. Simplify things by not requiring the
the stream to be specified.
In almost all cases, the printing of the table is surrounded by normal
printfs() that don't do explicit flushing and for which we don't check
the output stream status. Let's simplify most callers and skip this
step. The reason is not so much to avoid the extra step itself, but
instead to avoid the _handling_ of the potential failure. We generally
only want to print an error message for ENOMEM and other "internal"
errors, so strictly speaking we should filter out the errors from the
stream. By skipping the flush&check step we implicitly do this.
Trivial ordering/modernizing change that got highlighted by
claude and refined by keszybz to move to the modern systemd
style.
Thanks to keszybz for suggesting this.
This addresses
https://github.com/systemd/systemd/pull/41213#pullrequestreview-4002247053
which I somehow missed earlier.
Claude found a real issue for the case of manager_etc_hosts_flush().
We'll do the equivalent change in manager_static_records_flush() too,
even though it's not really necessary there, simply to keep things
nicely mirrored.
sd-resolved does dnssec "backwards" compared to most resolvers.
A typical strategy is to start from the DNS root and gather the
requisite keys on the way down, but sd-resolved requests the final
answer it wants and then goes searching for the requisite keys later.
We don't know in advance under which names we should expect to find
those keys, because we don't know the zone cuts a priori, but we can use
what we have found in prior responses to make an educated guess. This
was more or less the intent of 47690634f1, but it was partially
regressed in d840783db5 while fixing a bug handling totally empty
responses.
Fixes#37472
Ref: 47690634f1 ("resolved: don't request the SOA for every dns label")
Fixes: d840783db5 ("resolved: always progress DS queries")
sd-resolved does not support all the permissible DNSSEC signature
algorithms, and some are intentionally unsupported as a matter of
policy. Answers that can only be validated via unsupported algorithms
should be treated as if they were unsigned, per RFC4035 § 5.2.
Previously, sd-resolved tried to properly record insecure answers for
unsupported algortihms, but did not record this status for each of the
auxilliary DNSSEC transactions, so the primary transaction had no way to
know if there was a plausible DNSKEY with an unsupported signature
algorithm in the chain of trust.
This commit adds the insecure DNSKEYs that use unsupported algorithms to
the list of validated keys for each transaction, so that dependent
transactions can learn that a plausible chain of trust exists, even if
no authenticated one does, and report the insecure answer.
This should improve the situation in #35126.
This is an extension of the /etc/hosts concept, but can provide any kind
of RRs (well, actually, we only parse A/AAAA/PTR for now, but the
concept is open for more).
Fixes: #17791
When we are told to reload our configuration also flush out /etc/hosts
explicitly. This is particularly relevant since we suppress too frequent
reloads, and hence a synchronous way to force a reload is very useful.
sd-resolved does not support all the permissible DNSSEC signature
algorithms, and some are intentionally unsupported as a matter of
policy. Answers that can only be validated via unsupported algorithms
should be treated as if they were unsigned, per RFC4035§5.2.
Previously, sd-resolved tried to properly record insecure answers for
unsupported algortihms, but did not record this status for each of the
auxilliary DNSSEC transactions, so the primary transaction had no way to
know if there was a plausible DNSKEY with an unsupported signature
algorithm in the chain of trust.
This commit adds the insecure DNSKEYs that use unsupported algorithms to
the list of validated keys for each transaction, so that dependent
transactions can learn that a plausible chain of trust exists, even if
no authenticated one does, and report the insecure answer.
We often have a pattern where the same verb function is used for
multiple actions. This leads to an antipattern where we figure out what
action needs to be taken from argv[0] multiple times: often once in
parse_argv() to figure out what options are allowed, then once again
implicitly in dispatch_verb(), and then again in the action verb itself.
Let's allow passing a parameter into the verb to simplify this.
This matches a pattern we have in conf-parser.h, where we have both
void *userdata (more global) and void *data (per-config item). Here,
I opted for uintptr_t userdata. It seems that most of the time we'll
want to just pass an enum value. This works OK with no casts. I also
tried a void* and union. In both cases, much more boilerplate is needed:
either a cast or a macro to help avoid compiler warnings. uintptr_t
seems generic enough to cover foreseeable usecases with no fuss.
This is a noop refactoring. See next commit for an example.
Fix typo: DNS_TYPE_DNSKEY should be used instead of DNS_TYPE_KEY.
- DNS_TYPE_KEY is deprecated
- Source code at resolved-dns-trust-anchor.c#L313 handles
DNS_TYPE_DNSKEY records, but not DNS_TYPE_KEY
So DNS_TYPE_KEY is not referenced anywhere