Ntp: use values from network manager (via DHCP)

TL;DR: is it possible to use the ntp server provided by DHCP to network manager?

Context:
By default nixos sets the time using some ntp servers, like 0.nixos.pool.ntp.org… However in many universities a firewall blocks the ntp protocol on these servers:

$ nix-shell -p ntp
$ ntpdate -q 0.nixos.pool.ntp.org
22 Nov 17:06:57 ntpdate[4020886]: no server suitable for synchronization found

Therefore the computer cannot get a proper time. Instead, the university provides their own ntp server, that is advertised during the DHCP connection. We can get/check the ntp provided to network manager as follows:

$ nmcli connection show 'cwi-gast' | grep ntp
DHCP4.OPTION[8]:                        ntp_servers = 192.168.x.y
DHCP4.OPTION[18]:                       requested_ntp_servers = 1
$ ntpdate -q 192.168.x.y
server 192.168.x.y, stratum 3, offset +2.493988, delay 0.02779
22 Nov 16:51:37 ntpdate[3923570]: step time server 192.168.128.1 offset +2.493988 sec

It is possible to use:

networking.timeServers = options.networking.timeServers.default ++ [ "ntp.example.com" ]; 

to add a given ntp… but this need to be done on every network I’m going to. Since network managers is aware of the right ntp to use, wouldn’t it be possible to allow the systemd-timesyncd service to also get the address of the ntp server from DHCP/network manager?

EDIT
This wiki suggests that it’s impossible without using a trick involving a dispatcher restarting and reconfiguring systemd-timesyncd… So it seems like a limitation of Network manager. If I were using networkd instead it seems to be possible to configure it using:

systemd.network.config = {
  dhcpV4Config = { UseNTP = true; };
  dhcpV6Config = { UseNTP = true; };
}

even if it defaults to true already.

I’m not sure if the default dispatcher would work as-it on NixOs. I can see a dispatcher option for NM, but the above code will reconfigure/restart systemd-timesyncd on every new connection. The good thing it that it writes it in a different file for each connection so it may not collide with the timesyncd… It could work, I need to try it out! At least it’s good to know that it’s not a NixOs bug.

1 Like

Ok so I understand much better the status now (I’ve updated the wiki), depending on how you want to enable internet:

  • by default, NixOs uses a custom script to setup internet. This script, however, does not configure ntp from DHCP
  • networkd: networking.useNetworkd can be set to use systemd-networkd to configure the connections instead of the custom script (useNetworkd configures the systemd.network module to provide a decent default configuration). NTP from DHCP is automatically configured (the new NTP server is sent automatically to systemd-timesyncd) without any action, but in 2022 useNetworkd is considered experimental. But I tested it and it works great!
  • Network manager: Network Manager (networking.networkmanager.enable = true;), cannot directly configure NTP over DHCP… but there is a workaround: add a script that reconfigures systemd-timesyncd (with a new configuration file per connection) when a new connection is added and restart the service:
  ## To use, put this in your configuration, switch to it, and restart NM:
  ## $ sudo systemctl restart NetworkManager.service
  ## To check if it works, you can do `sudo systemctl status systemd-timesyncd.service`
  ## (it may take a bit of time to pick the right NTP as it may try the
  ## other NTP firsts)
  networking.networkmanager.dispatcherScripts = [
    {
      # https://wiki.archlinux.org/title/NetworkManager#Dynamically_set_NTP_servers_received_via_DHCP_with_systemd-timesyncd
      # You can debug with sudo journalctl -u NetworkManager-dispatcher -e
      # make sure to restart it:
      # sudo systemctl restart NetworkManager.service
      source = pkgs.writeText "10-update-timesyncd" ''
        [ -z "$CONNECTION_UUID" ] && exit 0
        INTERFACE="$1"
        ACTION="$2"
        case $ACTION in
        up | dhcp4-change | dhcp6-change)
            systemctl restart systemd-timesyncd.service
            if [ -n "$DHCP4_NTP_SERVERS" ]; then
              echo "Will add the ntp server $DHCP4_NTP_SERVERS"
            else
              echo "No DHCP4 NTP available."
              exit 0
            fi
            mkdir -p /etc/systemd/timesyncd.conf.d
            # <<-EOF must really use tabs to keep indentation correct… and tabs are often converted to space in wiki
            # so I don't want to risk strange issues with indentation
            echo "[Time]" > "/etc/systemd/timesyncd.conf.d/''${CONNECTION_UUID}.conf"
            echo "NTP=$DHCP4_NTP_SERVERS" >> "/etc/systemd/timesyncd.conf.d/''${CONNECTION_UUID}.conf"
            echo "config written"
            systemctl restart systemd-timesyncd.service
            echo "restarted"
            ;;
        down)
            rm -f "/etc/systemd/timesyncd.conf.d/''${CONNECTION_UUID}.conf"
            systemctl restart systemd-timesyncd.service
            ;;
        esac
        echo 'Done!'
      '';
    }
  ];

Note that it may take a bit of time (one minute maybe) for timesyncd to take the new configuration as it may try first the other NTP servers and timeout before trying the new NTP server.

2 Likes