diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index c7b51c02246..c6353b6f71e 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -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); diff --git a/src/resolve/resolved-dns-cache.h b/src/resolve/resolved-dns-cache.h index d8b71a3c2ad..3a2e2357a83 100644 --- a/src/resolve/resolved-dns-cache.h +++ b/src/resolve/resolved-dns-cache.h @@ -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, diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index ed65c24e922..f0203496cb6 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -379,11 +379,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); } @@ -1763,6 +1771,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; diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index 7aac4afe101..920bf1a796d 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -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);