[LINUX] How to get and set the NTP server name by DHCP

Motivation

In order to set the time of multiple hosts (Linux) in the isolated local network, we decided to run the NTP server on one of them and synchronize the time with the NTP client on the other. For each client host, we decided to set the NTP server address delivered by DHCP.

Setting up the client was more difficult.

The settings for the NTP server and the settings for distributing NTP server information with the DHCP server are described in various places. On the other hand, the client settings are highly environment-dependent and it took time to find appropriate information. It seems that the processing performed by the client side (Linux) at startup generally follows the following procedure.

  1. Launch a script (hook) when the DHCP client exits.
  2. The script started by the DHCP client updates the NTP client configuration file.
  3. Read the updated configuration file and start the NTP client.

Environment dependencies occur here ** DHCP clients (dhclient (ISC-DHCP), dhcpcd, NetworkManager's internal dhcp client, ...) and NTP clients (ntpd, Due to the large number of combinations ** of openntpd, chrony, systemd-timesyncd, ...). Depending on the Linux distribution, it seems that the DHCP and NTP packages adopted as defaults when upgrading the version may change, and I am addicted if I do not notice it. If a non-default (= not used) DHCP client or NTP client package is also installed, ** you may be worried about rewriting a configuration file that is not used and not doing what you want.

For Raspberry Pi OS

In Raspberry Pi OS (64bit, Debian buster based), the default DHCP client = dhcpcd, NTP client = systemd-timesyncd. The hooks called by DHCP are like /lib/dhcpcd/dhcpcd-hooks/50-ntp.conf. This file has a description for ntpd, ╩╗openntpd, chrony, but no description for systemd-timesyncd. Based on [Official website forum information](https://www.raspberrypi.org/forums/viewtopic.php?t=217832#p1340336), I added the following, and the NTP server dynamically started when the system started. It has been set and the time is set. ** There is a file called /etc/dhcp/dhclient-exit-hooks.d/timesyncd` that contains an implementation that seems to exist, but be aware that this is not used. ** **

/tmp/dhcpcd_ntp_conf(Correction part;diff output)


--- /etc/dhcpcd.conf.orig	2019-11-13 23:44:50.000000000 +0900
+++ /etc/dhcpcd.conf	2020-09-16 08:28:53.595999273 +0900
@@ -30,7 +30,7 @@ option classless_static_routes
 option interface_mtu
 
 # Most distributions have NTP support.
-#option ntp_servers
+option ntp_servers
 
 # A ServerID is required by RFC2131.
 require dhcp_server_identifier

/lib/dhcpcd/dhcpcd-hooks/50-ntp.conf(Postscript)


# Set NTP servers for systemd-timesyncd

confd=/run/systemd/timesyncd.conf.d

if [ -n "$new_ntp_servers" ] ; then
    set_servers() {
        mkdir -p "$confd"
        ( echo "# Created by dhcpcd hook";echo "[Time]"; echo "NTP=$new_ntp_servers" ) > "$confd/dhcp-ntp.conf"
        # Tell timesyncd it has an updated configuration
        systemctl try-reload-or-restart systemd-timesyncd
    }
    if $if_up; then
        set_servers
    fi
fi

By the way, in the systemd-timesyncd default configuration file (/lib/systemd/system/systemd-timesyncd.service.d/disable-with-time-daemon.conf), other NTP clients and VirtualBox services If the executable file of is present, nothing is done, so it is safer to add 50-ntp.conf instead of replacing it.

For Ubuntu MATE 20.04 LTS

For the image for Raspberry Pi (╩╗ubuntu-mate-20.04.1-beta2-desktop-arm64 + raspi.img), the internal dhcp client of NetworkManagerandsystemd-timesyncd are used. It seems to be a combination of . By default, dhclient is also installed, and /etc/dhcp/dhclient-exit-hooks.d/timesyncdis also provided, so if you manually executedhclienton the command line, the time will be synchronized. The default. So, I thought it would be better to adddhcp = dhclient to the [main] section of /etc/NetworkManager/NetworkManager.confso thatdhclientis used instead of internal dhcp. Looking at the log,dhclient` is throwing an error, and the hook is not called at the desired timing.

I gave up using dhclient because I had no choice, and decided to prepare a Dispather script for NetworkManager by referring to /etc/dhcp/dhclient-exit-hooks.d/timesyncd. Modify the environment variables and judgment strings according to the Official Manual, and /etc/NetworkManager/dispatcher.d/90-dhcp- Create timesyncd.

/etc/NetworkManager/dispatcher.d/90-dhcp-timesyncd


#!/bin/sh

TIMESYNCD_CONF=/run/systemd/timesyncd.conf.d/01-dhclient.conf

timesyncd_servers_setup_remove() {
    if [ -e $TIMESYNCD_CONF ]; then
        rm -f $TIMESYNCD_CONF
        systemctl try-restart systemd-timesyncd.service || true
    fi
}

timesyncd_servers_setup_add() {
    if [ ! -d /run/systemd/system ]; then
        return
    fi

    old_ntp_servers=$(sed -ne 's/^NTP=//gp')
    if [ -e $TIMESYNCD_CONF ] && [ "x$DHCP4_NTP_SERVERS" = "x$old_ntp_servers" ]; then
        return
    fi

    if [ -z "${DHCP4_NTP_SERVERS}" ]; then
        timesyncd_servers_setup_remove
        return
    fi

    mkdir -p $(dirname ${TIMESYNCD_CONF})
    cat <<EOF > ${TIMESYNCD_CONF}.new
# NTP server entries received from DHCP server
[Time]
NTP=$DHCP4_NTP_SERVERS
EOF
    mv ${TIMESYNCD_CONF}.new ${TIMESYNCD_CONF}
    systemctl try-restart systemd-timesyncd.service || true
}

logger -i -t "$0"  "action=${NM_DISPATCHER_ACTION}:NTP=${DHCP4_NTP_SERVERS}"

case $NM_DISPATCHER_ACTION in
    up|dhcp4-change)
        timesyncd_servers_setup_add
        ;;
    down)
        timesyncd_servers_setup_remove
        ;;
    *)  :
        ;;
esac

This file must be owned by root and given execute permissions.

% ls -l /etc/NetworkManager/dispatcher.d/90-dhcp-timesyncd
-rwxr-xr-x 1 root root 1140 Apr  2 02:55 /etc/NetworkManager/dispatcher.d/90-dhcp-timesyncd

By putting this script, the time is synchronized.

For JetPack 4.4 (Ubuntu 18.04 LTS based)

It seems that the previous version of Ubuntu also uses a combination of NetworkManager and systemd-timesyncd. Therefore, I thought that it would work with the same script as the previous section (Ubuntu MATE 20.04 LTS), but it did not work as expected as it was. It seems that the environment variable $ NM_DISPATCHER_ACTION is not set, probably because of the difference in the version of networkmanager-dispatcher. Therefore, instead, the expected behavior can be obtained by modifying the following so that the second argument at runtime is evaluated.

NetworkManager-Supports different versions of dispatcher


--- Ubuntu_MATE-20.04LTS/etc/NetworkManager/dispatcher.d/90-dhcp-timesyncd	2020-09-20 21:52:17.950941231 +0900
+++ JetPack-4.4/etc/NetworkManager/dispatcher.d/90-dhcp-timesyncd	2020-09-22 01:18:46.160691469 +0900
@@ -34,9 +34,9 @@ EOF
     systemctl try-restart systemd-timesyncd.service || true
 }
 
-logger -i -t "$0"  "action=${NM_DISPATCHER_ACTION}:NTP=${DHCP4_NTP_SERVERS}"
+logger -i -t "$0"  "action=${NM_DISPATCHER_ACTION:-${2}}:NTP=${DHCP4_NTP_SERVERS} [email protected]"
 
-case $NM_DISPATCHER_ACTION in
+case ${NM_DISPATCHER_ACTION:-$2} in
     up|dhcp4-change)
         timesyncd_servers_setup_add
         ;;

As an aside, Ubuntu 18.04 LTS's NetworkManager seems to use dhclient instead of the internal dhcp client.

For Ubuntu Server 20.04 LTS

It seems that it is a combination of internal dhcp clinet of systemd-networkd and systemd-timesyncd. The DHCP NTP server is set up without any special action. I couldn't find much information about systemd-networkd-dispatcher, so it's unclear how the DHCP-acquired address is passed to systemd-timesyncd.

For CentOS 7.8 (20.03), CentOS 8.2 (20.04)

It is a combination of NetworkManager and chrony, and the DHCP NTP server is set up without doing anything. As an aside, it seems that CentOS 7 uses dhclient and CentOS 8 uses NetworkManager's internal dhcp client.

Recommended Posts

How to get and set the NTP server name by DHCP
How to set the server time to Japanese time
[Python Kivy] How to get the file path by dragging and dropping
How to get the variable name itself in python
How to unprefix the DB name used by pytest-django
How to get all the keys and values in the dictionary
How to get the Python version
[Linux] [C / C ++] How to get the return address value of a function and the function name of the caller
How to get followers and followers from python using the Mastodon API
[Python] How to get the first and last days of the month
How to get the pixel value of the point from the satellite image by specifying the latitude and longitude
How to get colored output to the console
How to get a specific column name and index name in pandas DataFrame
How to get the date and time difference in seconds with python
[Django] How to get data by specifying SQL.
How to erase the characters output by Python
How to get the files in the [Python] folder
How to set up a local development server
How to get started with the 2020 Python project (windows wsl and mac standardization)
python I don't know how to get the printer name that I usually use.
How to get the notebook name you are currently using in Google Colab
I want to get the file name, line number, and function name in Python 3.4
How to get the "name" of a field whose value is limited by the choice attribute in Django's model
How to get the number of digits in Python
How to execute a schedule by specifying the Python time zone and execution frequency
[Blender] How to get the selection order of vertices, edges and faces of an object
How to use the grep command and frequent samples
How to check the Java version used by Maven
[Blender] How to dynamically set the selection of EnumProperty
[Introduction to Udemy Python3 + Application] 30. How to use the set
How to use argparse and the difference between optparse
How to set up and compile your Cython environment
How to get RGB and HSV histograms in OpenCV
How to get the current weather data and display it on the GUI while updating it automatically
How to get only the data you need from a structured data set using a versatile method
How to get rid of server custom emoji in message.content
How to switch the configuration file to be read by Python
How to test the attributes added by add_request_method of pyramid
Foreigners talk: How to name classes and methods in English
[Python] How to set variable names dynamically and speed comparison
How to set the html class attribute in Django's forms.py
Build a Python environment and transfer data to the server
How to get the last (last) value in a list in Python
How to get into the python development environment with Vagrant
How to set the extended iso8601 format date to the Dataframe index
[Shell] How to get the remote default branch in Git
[Introduction to Python] How to get data with the listdir function
To get the name of the primitive etc. generated immediately before
How to use the generator
How to use the decorator
How to increase the axis
How to start the program
[Django Learned with the Devil's Blade] How to get a query set for forward / reverse reference
I tried ranking the user name and password of phpMyAdmin that was targeted by the server attack
How to display the CPU usage, pod name, and IP address of a pod created with Kubernetes
How to set cron for regular Python scraping on Sakura server.
How to set a shortcut to switch full-width and half-width with IBus
How to set the output resolution for each keyframe in Blender
I want to get the name of the function / method being executed
Overview of how to create a server socket and how to establish a client socket
How to pass and study the Python 3 Engineer Certification Basic Exam