Configuring an NTP client daemon

Selecting NTP servers

Before we can configure an NTP client we need to determine the addresses of some public NTP servers to use as sources of time data. Thankfully the NTP Public Services Project maintains a list of servers which are available for public use. The NTP Public Services Project also maintains a round-robin DNS pool of public NTP servers, both globally and geographically, which we shall be using in our examples, known as the NTP Pool Time Servers.

Setting the clock during boot

Most NTP clients operate continuously in the background sending and receiving queries and responses periodically to maintain an accurate time reference. They then use this information to update the speed at which the clock on the host ticks to slowly bring it into line with the reference time and then subsequently to maintain the synchronisation of system time to the reference time as closely as possible.

When a computer boots into an operating system the time is set from the internal clock which may be out of sync with real time by a considerable margin. Clearly, using the background tuning offered by most NTP clients a large difference between real and reference time may take a long time to be resolved as the clock speed is only ever adjusted by a very small amount. For this reason we are going to configure the ntp-client init script to synchronise local time to the reference time during the boot process.

As you can see from the example below the configuration is very simple. The first line specifies the command to use to synchronise the clock, in this case the ntpdate application. The second entry specifies the options to be used when running the ntpdate application, in this case -s to write logging information to the system log, -b to force the clock to be set not stepped and -u to use an unprivileged source port for outgoing connections. The remainder of this entry lists the servers we shall use for synchronisation.

/etc/conf.d/ntp-client
NTPCLIENT_CMD="ntpdate"

NTPCLIENT_OPTS="-s -b -u \
0.nl.pool.ntp.org 1.nl.pool.ntp.org \
2.nl.pool.ntp.org 3.nl.pool.ntp.org"
Information:
In the above example we have used NTP servers from the nl.pool.ntp.org pool. This is a geographic pool for The Netherlands and, unless you happen to be configuring a system in that geographical region, you should modify these entries to reflect the location of your system. Roaming systems such as lap-top computers or mobile phones should use the global pool.ntp.org pool.
 

With the configuration complete we can start the ntp-client initialisation script to synchronise the local time to the reference time now and add it to the default run-level so that it will be run on every boot using the commands shown below.

lisa /etc/init.d/ntp-client start
lisa rc-update add ntp-client default

Keeping the clock synchronised to remote servers

Whilst the ntp-client script takes care of synchronising the clock on every boot it does nothing to improve the accuracy of the internal clock after that. If we wish to have our system periodically check the drift between local and reference time and attempt to reduce that drift to the minimum possible we need to configure an NTP daemon.

Before we can create a configuration for the NTP daemon we need to move the supplied configuration out of the way, preferably somewhere it can be referenced in the future as shown below.

lisa mv /etc/ntp.conf /etc/ntp.conf.example

As you can see from the example configuration provided below the content is very similar to that used when configuring the ntp-client script although the format is totally different. There are also additional sections which configure policy for the NTP daemon.

The first block simply lists the servers we shall be using as reference sources as before. Each server is specified on its own line and as many servers as desired can be listed although four is the preferred number as it allows a good range of options for the selection algorithm without placing unnecessary load on the NTP server pool or the local host.

The second configuration block in the example below sets the policy for the servers we shall be contacting. In this case we have specified that the servers will not be able to modify our configuration, query our server or send trap events as all of these would open potential attack vectors while providing no additional functionality.

The third section sets the policy for clients of this NTP daemon. The first line sets the default policy for all clients to ignore ensuring that no hosts which are not mentioned in the configuration file are able to interact with the NTP daemon in any way. The second line allows any connection from the local loopback address to query the server but indicates that remote configuration modification, peering requests and trap events are not allowed.

Finally we specify the location of the drift file which is used by the NTP daemon to store the current clock drift.

/etc/ntp.conf
# List of servers to sync with
server 0.nl.pool.ntp.org
server 1.nl.pool.ntp.org
server 2.nl.pool.ntp.org
server 3.nl.pool.ntp.org

# Set policy for servers
restrict 0.nl.pool.ntp.org nomodify noquery notrap
restrict 1.nl.pool.ntp.org nomodify noquery notrap
restrict 2.nl.pool.ntp.org nomodify noquery notrap
restrict 3.nl.pool.ntp.org nomodify noquery notrap

# Set default policy for clients
restrict default ignore
restrict 127.0.0.0 mask 255.0.0.0 nomodify nopeer notrap

# Location of the "drift" file
driftfile /var/lib/ntp/ntp.drift

With the configuration complete we can start the NTP daemon and add it to the default run-level so that it will be started on every boot using the commands shown below.

lisa /etc/init.d/ntpd start
lisa rc-update add ntpd default

Monitoring clock synchronisation progress

Once we have started the NTP daemon we can monitor the synchronisation process using the command shown below which uses the watch application to repeatedly run the ntpq application to print a list of our connected synchronisation peers and their status.

lisa watch -n 1 ntpq -p

Assuming that the NTP daemon is configured and operating correctly you should see output similar to that shown below.

     remote           refid      st t when poll reach   delay   offset  jitter 
============================================================================== 
 isi.xelerance.c 193.0.0.228      2 u    8   64    1   23.590  -26.090   0.001 
 metronoom.dmz.c .PPS.            1 u    7   64    1   22.386   41.352   0.001 
 oslo.illian.net 193.67.79.202    2 u    6   64    1   21.827   41.225   0.001 
 ran.r3blog.nl   193.204.114.232  3 u    5   64    1   22.233   41.119   0.001 

As you can see the first column lists the synchronisation peers which we specified in our configuration although the actual reverse DNS names of the peers are used here not the pool aliases we used in our configuration. The second column lists the address of the reference peer which this server is currently synchronised with unless that peer is from stratum one in which case the string .PPS. is displayed instead.

The third and fourth columns indicate the stratum which the time server belongs to and the type of connection we are using, in this case unicast IP datagrams, while the fifth and sixth columns indicate when the next time query will be sent.

The remaining columns are fairly self explanatory and detail the current reach of the remote peer, the round-trip delay experienced by the last query, the offset from the current time which was indicated in the response, and the average computed jitter.

     remote           refid      st t when poll reach   delay   offset  jitter 
============================================================================== 
 isi.xelerance.c 193.0.0.228      2 u   10   64   17   22.428  -22.430   2.978 
 metronoom.dmz.c .PPS.            1 u    7   64   17   20.497   43.741   1.402 
*oslo.illian.net 193.67.79.202    2 u    9   64   17   20.459   42.872   1.157 
 ran.r3blog.nl   193.204.114.232  3 u    5   64   17   20.912   42.268   1.008 

Once the NTP daemon has been running for some time it will select a primary synchronisation peer which will be used to calculate the current distance from the current real time as well as the drift of our local clock. The example above shows that this is indicated using a * symbol next to the name of the remote peer.

     remote           refid      st t when poll reach   delay   offset  jitter 
============================================================================== 
-isi.xelerance.c 193.0.0.228      2 u   14   64  177   20.258  -24.377   1.919 
+metronoom.dmz.c .PPS.            1 u   16   64  177   19.791   44.894   1.862 
*oslo.illian.net 193.67.79.202    2 u   19   64  177   19.668   44.138   1.879 
+ran.r3blog.nl   193.204.114.232  3 u   11   64  177   20.472   41.839   1.445 

Eventually the NTP daemon will select one or more fallback synchronisation peers which will be indicated using a + symbol next to their names. It may also decide to reject the information from certain remote peers if they are deemed too far from the current time or their jitter or delay values are too high. Rejected peers are indicated by a - symbol next to their host name. As you can see the NTP daemon does not automatically select synchronisation peers from the lowest stratum but instead selects them on the basis of which one would provide the best time synchronisation.