]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: automatically flush caches on clock change
authorLennart Poettering <lennart@poettering.net>
Thu, 5 Nov 2020 13:17:37 +0000 (14:17 +0100)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 2 Dec 2020 22:25:17 +0000 (07:25 +0900)
DNSSEC validation takes the system clock into account to validate
signatures. This means if we had incorrect time and the time is then
changed to the correct one we should flush out everything and
re-validate taking the new time into account.

(This logic will also trigger after system suspend, which is not bad
either, given that quite possibly we are connected to a different
network, and thus would get different DNS data, without us noticing
otherwise via link beat).

src/resolve/resolved-bus.c
src/resolve/resolved-manager.c
src/resolve/resolved-manager.h

index dca9b885febf2ed9a451985eccd5a68db82ef5c0..9a4789543a0636cceba27d590967065f2aa77ecc 100644 (file)
@@ -1762,7 +1762,7 @@ static int bus_method_flush_caches(sd_bus_message *message, void *userdata, sd_b
         assert(message);
         assert(m);
 
-        manager_flush_caches(m);
+        manager_flush_caches(m, LOG_INFO);
 
         return sd_bus_reply_method_return(message, NULL);
 }
index 03319221247154e332f9db915d0b1faad0964299..d721e767499913951dc7412ad1d565fb14dc6d2d 100644 (file)
@@ -313,6 +313,54 @@ static int manager_network_monitor_listen(Manager *m) {
         return 0;
 }
 
+static int manager_clock_change_listen(Manager *m);
+
+static int on_clock_change(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+        Manager *m = userdata;
+
+        assert(m);
+
+        /* The clock has changed, let's flush all caches. Why that? That's because DNSSEC validation takes
+         * the system clock into consideration, and if the clock changes the old validations might have been
+         * wrong. Let's redo all validation with the new, correct time.
+         *
+         * (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 */);
+
+        /* The clock change timerfd is unusable after it triggered once, create a new one. */
+        return manager_clock_change_listen(m);
+}
+
+static int manager_clock_change_listen(Manager *m) {
+        _cleanup_close_ int fd = -1;
+        int r;
+
+        assert(m);
+
+        m->clock_change_event_source = sd_event_source_unref(m->clock_change_event_source);
+
+        fd = time_change_fd();
+        if (fd < 0)
+                return log_error_errno(fd, "Failed to allocate clock change timer fd: %m");
+
+        r = sd_event_add_io(m->event, &m->clock_change_event_source, fd, EPOLLIN, on_clock_change, m);
+        if (r < 0)
+                return log_error_errno(r, "Failed to create clock change event source: %m");
+
+        r = sd_event_source_set_io_fd_own(m->clock_change_event_source, true);
+        if (r < 0)
+                return log_error_errno(r, "Failed to pass ownership of clock fd to event source: %m");
+        TAKE_FD(fd);
+
+        (void) sd_event_source_set_description(m->clock_change_event_source, "clock-change");
+
+        return 0;
+}
+
 static int determine_hostname(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) {
         _cleanup_free_ char *h = NULL, *n = NULL;
 #if HAVE_LIBIDN2
@@ -549,7 +597,7 @@ static int manager_sigusr2(sd_event_source *s, const struct signalfd_siginfo *si
         assert(si);
         assert(m);
 
-        manager_flush_caches(m);
+        manager_flush_caches(m, LOG_INFO);
 
         return 0;
 }
@@ -642,6 +690,10 @@ int manager_new(Manager **ret) {
         if (r < 0)
                 return r;
 
+        r = manager_clock_change_listen(m);
+        if (r < 0)
+                return r;
+
         r = manager_connect_bus(m);
         if (r < 0)
                 return r;
@@ -709,6 +761,7 @@ Manager *manager_free(Manager *m) {
 
         sd_netlink_unref(m->rtnl);
         sd_event_source_unref(m->rtnl_event_source);
+        sd_event_source_unref(m->clock_change_event_source);
 
         manager_llmnr_stop(m);
         manager_mdns_stop(m);
@@ -1440,7 +1493,7 @@ bool manager_routable(Manager *m) {
         return false;
 }
 
-void manager_flush_caches(Manager *m) {
+void manager_flush_caches(Manager *m, int log_level) {
         DnsScope *scope;
 
         assert(m);
@@ -1448,7 +1501,7 @@ void manager_flush_caches(Manager *m) {
         LIST_FOREACH(scopes, scope, m->dns_scopes)
                 dns_cache_flush(&scope->cache);
 
-        log_info("Flushed all caches.");
+        log_full(log_level, "Flushed all caches.");
 }
 
 void manager_reset_server_features(Manager *m) {
index 739683cbb5276812636004c63e8765e575583798..120b63dc8c957c8ab38b9de99a17618f20eadbde 100644 (file)
@@ -143,6 +143,8 @@ struct Manager {
         Hashmap *polkit_registry;
 
         VarlinkServer *varlink_server;
+
+        sd_event_source *clock_change_event_source;
 };
 
 /* Manager */
@@ -188,7 +190,7 @@ void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResource
 
 bool manager_routable(Manager *m);
 
-void manager_flush_caches(Manager *m);
+void manager_flush_caches(Manager *m, int log_level);
 void manager_reset_server_features(Manager *m);
 
 void manager_cleanup_saved_user(Manager *m);