]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolve: reload /etc/hosts on inode change
authorGiedrius Statkevičius <giedriuswork@gmail.com>
Sun, 22 Mar 2020 20:40:18 +0000 (22:40 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 3 Apr 2020 15:34:10 +0000 (17:34 +0200)
On certain distributions such as NixOS the mtime of `/etc/hosts` is
locked to a fixed value. In such cases, only checking the last mtime of
`/etc/hosts` is not enough - we also need to check if the st_ino/st_dev
match up. Thus, let's make sure make sure that systemd-resolved also
rereads `/etc/hosts` if the inode or the device containing `/etc/hosts` changes.

Test script:

```bash
hosts="/etc/hosts"
echo "127.0.0.1 testpr" > "hosts_new"
mv "hosts_new" "$hosts"
resolvectl query testpr || exit 1
mtime="$(stat -c %y "$hosts")"
echo "127.0.0.1 newhost" > "hosts_tmp"
touch -d "$mtime" "hosts_tmp"
install -p "hosts_tmp" "$hosts"
sleep 10
resolvectl query newhost || exit 1
rm -f "hosts_tmp"
```

Closes #14456.

src/resolve/resolved-etc-hosts.c
src/resolve/resolved-manager.c
src/resolve/resolved-manager.h

index e6bf20db54f54210e5e1649dc38b85ea657d18eb..c2839d425ad256e6eac44fbeb8e7b16a74e2fe6b 100644 (file)
@@ -37,6 +37,8 @@ void etc_hosts_free(EtcHosts *hosts) {
 void manager_etc_hosts_flush(Manager *m) {
         etc_hosts_free(&m->etc_hosts);
         m->etc_hosts_mtime = USEC_INFINITY;
+        m->etc_hosts_ino = 0;
+        m->etc_hosts_dev = 0;
 }
 
 static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
@@ -224,8 +226,9 @@ static int manager_etc_hosts_read(Manager *m) {
                         return 0;
                 }
 
-                /* Did the mtime change? If not, there's no point in re-reading the file. */
-                if (timespec_load(&st.st_mtim) == m->etc_hosts_mtime)
+                /* Did the mtime or ino/dev change? If not, there's no point in re-reading the file. */
+                if (timespec_load(&st.st_mtim) == m->etc_hosts_mtime &&
+                    st.st_ino == m->etc_hosts_ino && st.st_dev == m->etc_hosts_dev)
                         return 0;
         }
 
@@ -249,6 +252,8 @@ static int manager_etc_hosts_read(Manager *m) {
                 return r;
 
         m->etc_hosts_mtime = timespec_load(&st.st_mtim);
+        m->etc_hosts_ino = st.st_ino;
+        m->etc_hosts_dev = st.st_dev;
         m->etc_hosts_last = ts;
 
         return 1;
index 4f72077720b1ca8aad518d482759bdf961f7a56d..df25907a4c5c45ee702183c7481237da2cbc57f5 100644 (file)
@@ -591,6 +591,8 @@ int manager_new(Manager **ret) {
                 .need_builtin_fallbacks = true,
                 .etc_hosts_last = USEC_INFINITY,
                 .etc_hosts_mtime = USEC_INFINITY,
+                .etc_hosts_ino = 0,
+                .etc_hosts_dev = 0,
                 .read_etc_hosts = true,
         };
 
index 7f7d3a6b9c6df65047c702463e4ee28ebcd47e86..446f258b49ba63dd99de01944e6caf31dedde2fa 100644 (file)
@@ -127,6 +127,8 @@ struct Manager {
         /* Data from /etc/hosts */
         EtcHosts etc_hosts;
         usec_t etc_hosts_last, etc_hosts_mtime;
+        ino_t etc_hosts_ino;
+        dev_t etc_hosts_dev;
         bool read_etc_hosts;
 
         /* Local DNS stub on 127.0.0.53:53 */