Network Time Synchronization

I noticed that my Ubuntu desktop computers are synchronizing their clocks with ntp.ubuntu.com. This happens even the if they get addesses of local NTP-servers trough DHCP.

timesyncd

On Ubuntu the system clock is synchronized by the timesyncd systemd service. timesyncd was introduced with Ubuntu 16.04 and replaced chrony. chrony did replace the now depracated classic ntp client.

The timesyncd service is configured trough its configuration file /etc/systemd/timesyncd.conf.

The manpage of timesyncd.conf(5) says the timeservers to contact are set with a space-separated list of NTP server host names or IP addresses in the “NTP=” seeting.

During runtime this list is combined with any per-interface NTP servers acquired from systemd-networkd.

The file also contains a “FallbackNTP=” setting, which is only used no other NTP server information is known.

If neither “NTP=” nor “FallbackNTP=” are set, a compiled-in list of NTP servers is used instead.

Taking a look at the configuration shows that nothing is set, but the compiled-in options are shown:

#  This file is part of systemd.
#
# Entries in this file show the compile time defaults.
# You can change settings by editing this file.
# Defaults can be restored by simply deleting this file.
#
# See timesyncd.conf(5) for details.

[Time]
#NTP=
#FallbackNTP=ntp.ubuntu.com
#RootDistanceMaxSec=5
#PollIntervalMinSec=32
#PollIntervalMaxSec=2048

So I assume that ntp.ubuntu.com is used as time-server because the list remains empty, even if our DHCP sever is sending out NTP server addesses to use.

Let’s change that first, so it will no longer phone home by editing /etc/systemd/timesyncd.conf:

#  This file is part of systemd.
#
# See timesyncd.conf(5) for details.

[Time]
# Set at least one numerical IP address as fallback
# to avoid DNSSEC chicken-and-egg problems.
#   Init7 NTP servers:
#       aquila.init7.net    - 82.197.164.46
#       eudyptula.init7.net - 82.197.188.130
FallbackNTP=ch.pool.ntp.org 82.197.188.130 82.197.164.46

Restart the service afterwards:

$ sudo systemctl restart systemd-timesyncd.service

systemd-networkd

In systemd-networkd is configured via /etc/systemd/networkd.conf and various configuration file in the directory /etc/systemd/network/.

But the manpage for the systemd network-configuration, states that you can either set an NTP server address yourself with the “NTP=” setting in the “[Network]” section, or you can set the option “UseNTP=” in the “[DHCPV4]” and “[DHCPv6]” sections. Both are “true” by default.

So if NTP servers supplied trough DHCP are passed on to timesyncd by default, why isn’t that actually happening?

As it turns out, Ubuntu Desktop doesn’t actually use systemd-networkd.service. Its disabled in favor of the NetworkManager.

NetworkManager

Contrary to systemd-networkd, NetworkManager is not capable to communicate with systemd-timesyncd to set the NTP server addesses automatically.

But with NetworkManager, scripts can be placed in specific subdirectories of the /etc/NetworkManager/dispatcher.d/ directory to be triggered by the NetworkManager-dispatcher.service on related network events.

The following script is inspired by the ArchLinux wiki, to be placed in /etc/NetworkManager/dispatcher.d/10-update-timesyncd:

#!/usr/bin/env dash
#
# Setup timesyncd to use NTP servers received by DHCP.
# Time server addresses are added or removed for each connection.
#
set -e

INTERFACE=$1
ACTION=$2
_CONF_DIR=/etc/systemd/timesyncd.conf.d

# Do we have a connection ID?
if [ -z "$CONNECTION_UUID" ]; then
    exit 0
fi

# Is the timesyncd service currently active?
_timesyncd_state="$( systemctl show --property "ActiveState" systemd-timesyncd.service )"

# Do we have the overlay configuration directory for timesyncd
if [ ! -d "$_CONF_DIR" ]; then

    # Create it
    mkdir -p "$_CONF_DIR"
fi

case $ACTION in

    # Network just went up or configuration received by DHCP has changed
    up | vpn-up | dhcp4-change | dhcp6-change)

        # Did we receive any NTP server addresses by DHCP?
        if [ -z "$DHCP4_NTP_SERVERS" ] && [ -z "$DHCP6_NTP_SERVERS" ]; then

            # Neither IPv6 nor IPv4 NTP server address received.
            exit 0
        fi

        if [ -n "$DHCP4_NTP_SERVERS" ]; then
            _ntp_servers="$_ntp_servers $DHCP4_NTP_SERVERS"
        fi
        if [ -n "$DHCP6_NTP_SERVERS" ]; then
            _ntp_servers="$_ntp_servers $DHCP6_NTP_SERVERS"
        fi

        # Create a connection-specific timesyncd configuration file
        exec > "${_CONF_DIR}/${CONNECTION_UUID}.conf"
            echo "# Generated by $(basename "$0")for $INTERFACE"
            echo "[Time]"
            echo "NTP=${_ntp_servers}"

        if [ "$_timesyncd_state" = "ActiveState=active" ]; then

            # Restart the timesyncd service
            systemctl restart systemd-timesyncd
        fi
        ;;

    # Connection went down
    down | vpn-down)

        # Remove the timesyncd configuration for this connection
        rm -f "${_CONF_DIR}/${CONNECTION_UUID}.conf"

        if [ "$_timesyncd_state" = "ActiveState=active" ]; then

            # Restart the timesyncd service
            systemctl restart systemd-timesyncd
        fi
        ;;
esac

Make it executable and writable by the root user only:

$ chmod 0744 /etc/NetworkManager/dispatcher.d/10-update-timesyncd

References