1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-21 02:50:18 +03:00

Force DNS cache entries to be stale on time change, rather than blindly flushing

On laptops and other devices which suspend frequently and are connected to WiFi, each suspension results in a loss of all cached DNS entries. This is problematic because some applications maintain their own DNS caches, which they also refresh immediately after suspensions. On WiFi networks that take some time to connect to, this results in applications getting a lot of non-authoritative NXDOMAIN responses in their caches, before systemd-resolved can get a connection to a real DNS server.

This case should be prevented by the caching of stale data, but the blind flush of the cache prevents this. Further, the cache flushes disrupt statistics, and are unneeded to achieve the re-validation of DNSSEC responses. Nevertheless, maintain the flushing behavior on systems cases with no stale data retention, since it is possible that we are on an intranet with a local DNS server which was changed during suspension.
This commit is contained in:
Calum McConnell 2025-02-19 23:55:51 -05:00 committed by GitHub
parent 5dbc4f37c5
commit 48317bfc4b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 37 additions and 5 deletions

View File

@ -171,6 +171,17 @@ void dns_cache_flush(DnsCache *c) {
c->by_expiry = prioq_free(c->by_expiry);
}
void dns_cache_force_stale(DnsCache *c) {
DnsCacheItem *item;
assert(c);
/* Force all entries to be stale; they will be cleaned out properly as appropriate*/
HASHMAP_FOREACH(item, c->by_key) {
item->until_valid=1;
}
}
static void dns_cache_make_space(DnsCache *c, unsigned add) {
assert(c);

View File

@ -22,6 +22,7 @@ typedef struct DnsCache {
void dns_cache_flush(DnsCache *c);
void dns_cache_prune(DnsCache *c);
void dns_cache_force_stale(DnsCache *c);
int dns_cache_put(
DnsCache *c,

View File

@ -378,11 +378,19 @@ static int on_clock_change(sd_event_source *source, int fd, uint32_t revents, vo
*
* (Also, this is triggered after system suspend, which is also a good reason to drop caches, since
* we might be connected to a different network now without this being visible in a dropped link
* carrier or so.) */
log_info("Clock change detected. Flushing caches.");
manager_flush_caches(m, LOG_DEBUG /* downgrade the functions own log message, since we already logged here at LOG_INFO level */);
* carrier or so.)
*
* That being said, old data isn't neccessarily invalid; so if we can't reach upstream DNS immediately,
* provide stale data if configured to. */
if(m->stale_retention_usec == 0){
log_info("Clock change detected. Flushing caches.");
manager_flush_caches(m, LOG_DEBUG /* downgrade the functions own log message, since we already logged here at LOG_INFO level */);
} else {
log_info("Clock change detected. Marking caches as stale.");
manager_force_caches_stale(m, LOG_DEBUG /* downgrade the functions own log message, since we already logged here at LOG_INFO level */);
}
/* The clock change timerfd is unusable after it triggered once, create a new one. */
return manager_clock_change_listen(m);
}
@ -1762,6 +1770,17 @@ void manager_flush_caches(Manager *m, int log_level) {
log_full(log_level, "Flushed all caches.");
}
void manager_force_caches_stale(Manager *m, int log_level) {
assert(m);
LIST_FOREACH(scopes, scope, m->dns_scopes) {
dns_cache_force_stale(&scope->cache);
dns_cache_prune(&scope->cache); /* it is likley that pruning is needed*/
}
log_full(log_level, "All cached data marked stale.");
}
void manager_reset_server_features(Manager *m) {
Link *l;

View File

@ -221,6 +221,7 @@ void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResource
bool manager_routable(Manager *m);
void manager_flush_caches(Manager *m, int log_level);
void manager_force_caches_stale(Manager *m, int log_level);
void manager_reset_server_features(Manager *m);
void manager_cleanup_saved_user(Manager *m);