1

According to this answer, DHCPd lease files are cleared every hour. The goal is to back up the leases file continuously, so there is never a lease lost. This is made difficult since it is unclear whether the hour timer is based on system time (eg the file is rewritten at 1am, 2am, 3am etc) or process time (service_start + 1h, service_start + 2h, etc). Say the leases file is cleared at exactly 3am, and a lease is granted at 2:58:55; the service that backs up the lease file would need to run, quickly, before the file is cleaned.

The DHCPd process makes its own backup of the file to /var/lib/dhcpd/dhcpd.leases~. The best bet then seems to be to make a script that backs up this file to another location every hour. But if the DHCPd process is restarted and the timer is relative to the process, it would be possible for the hour mark on the backup tasks to align, which might end in one process reading while the other writes, and that could mangle the file (depending on how it's done). So the backup task would need some knowledge of when DHCPd starts. This is getting complicated.

What is the 'correct' way to back up the DHCPd leases file, so no leases are lost?

vpseg
  • 23
  • 3

1 Answers1

1

From DHCP sources:

      if (snprintf (backfname, sizeof backfname, "%s~", path_dhcpd_db)            >= sizeof backfname)

[...]

      if (unlink (backfname) < 0 && errno != ENOENT) { 

[...]

      if (link(path_dhcpd_db, backfname) < 0) { 

The previous backup file is deleted, then the current lease file is hardlinked as backup with a trailing ~.

On Linux, with the inotify(7) event facility, a hardlink is seen as a creation event.

I would suggest to use inotifywait (from inotify-tools package) to signal when such event happened. One should expect the apparition of /var/lib/dhcpd/dhcpd.leases~ which is then directly ready for backup (it's a hardlink to the original). As the file will be a different file (different inode) each time, it's the directory that should be watched for proper detection, and for example the --include option can be used to simplify shell processing (no processing, even the read line is discarded in a dummy variable):

inotifywait -m -e create --include dhcpd.leases~ /var/lib/dhcpd | while read dummy; do
    do_backup /var/lib/dhcpd/dhcpd.leases~
done

If the command is not recent enough, it might not understand --include in such case, the test has to be done in the event loop:

inotifywait -m -e create /var/lib/dhcpd | while read -r dir event filename; do
    if [ "$filename" = dhcpd.leases~ ]; then
        do_backup /var/lib/dhcpd/dhcpd.leases~
    fi
done

Alternatively, the incron package (available at least on CentOS 8 Stream), could be used with an entry similar to:

/var/lib/dhcpd IN_CREATE,recursive=false if_correct_file_do_backup $#

with if_correct_file_do_backup being for example a shell checking this was the intended filename:

#!/bin/sh

if [ "$1" = dhcpd.leases~ ]; then
    do_backup /var/lib/dhcpd/dhcpd.leases~
fi
A.B
  • 9,037
  • 2
  • 19
  • 37