What goes on behind the Network Time Protocol ?

Several times, I had discussions with friends on how NTP works! What is the logic behind NTP and its configurations? We noticed that there are several terms and calculations to grasp especially when it comes to debugging. Well, I decided to make a research on it and shed some ideas on NTP - Network Time Protocol. These recent days, we have noticed several vulnerabilities and attacks going on the NTP servers. NTP is a protocol designed to synchronize the clocks of computers over a network.

Photo credits: networktimefoundation.org
Photo credits: networktimefoundation.org

NTP is a utility where timestamps are used. Examples are logs, database replications, the time packets  exchanged in a network. NTP uses its own binary format and runs on port 123 UDP. RFC 1305 and RFC 2030 give detailed explanations of NTP.

The logic behind NTP

In brief, packets are exchanged between the NTP server and the client in the following order. It is to be noted that latency is an important issue when it comes to NTP:

  1. The NTP client will send a request with a timestamp.
  2. The NTP server will return the packet with 3 timestamps.
    • echo of the client timestamp
    • The timestamp of the received timestamp by the server
    • The timestamp response sent by the server.
  3. The client will then estimate the offset (the difference in timestamps between the client and the server)

A client may have several NTP servers configured, but will synchronize with only one NTP server. A server may also take some time to respond to a client depending when it is not busy. NTP packets are exchanged between 64 - 1024 seconds for each server. - This configurations are called "minpoll" and "maxpoll"

Some basic configuration on a CentOS 7 machine

The command timedatectl can be used to check if NTP is enabled or not

[[email protected] ~]# timedatectl | egrep -i ntp
     NTP enabled: yes
NTP synchronized: yes

You can also check if the service is running using the following command;

systemctl status chronyd.service

The configuration file is located by default at /etc/chrony.conf . You will notice that the NTP servers are configured by default in that file.

[[email protected] ~]# head -n 7 /etc/chrony.conf 

# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
server 0.centos.pool.ntp.org iburst
server 1.centos.pool.ntp.org iburst
server 2.centos.pool.ntp.org iburst
server 3.centos.pool.ntp.org iburst

You can check if your machine are synchronised from the sources with the following command. The column Name/IP address are the location from where the time is being synchronized.

[[email protected] ~]# chronyc sources


210 Number of sources = 4
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^+ cpt-ntp.mweb.co.za            2   6   367    40    +29ms[  +29ms] +/-  151ms
^* cpto-afr-01.time.jpbe.de      2   7   377    43    +69ms[  +66ms] +/-  178ms
^+ ntp2.inx.net.za               2   6   377    43    +64ms[  +64ms] +/-  181ms
^+ ns.bitco.co.za                3   7   377   107    +79ms[  +77ms] +/-  199ms

A drift means a deviation. A drift happens when  the hardware clock is either fast or slow compared to the NTP server clock. The drift file contains 2 values. If it's a positive number, it means the clock is fast from the NTP server whereas if it is a negative number, it means the clock is slow compared to the NTP server. Here i have a slow clock.

[[email protected] ~]# cat /var/lib/chrony/drift 

         -870.203668          1484.980507
The Maths - How the NTP client adjust its response from the NTP server

Now, we will get into the math behind the logic as discussed previously what happens when the NTP client request the time from the NTP server.

  1. NTP Client A send request to server X - Let's assume A=100 where 100 is the time of the client
  2. NTP Server X received the request after some secs. - Let's assume X= 150 where 150 is the time of the server.
  3. Being given that, the request from NTP client is not necessarily served immediately, there is lapse of time at this point. let's assume that X is now 160
  4. We now have 3 values i.e; The time the client sent the request, the time (real time) the server received the request and the time the server want to respond back.
  5. Now the NTP client gets the request back at 120. This is because the NTP client has its own time.
  6. Client will now determine the time using the formulae B-A - (Y-X) which means 120-100-(160-150) = 10 seconds
  7. Client assumed that the time it took to get the response from server to client is 10/2 = 5 seconds. Assuming 5 seconds is the latency.
  8. Now the client adds 5 seconds to  the server time at the time it received the response which makes 160 +5 = 165 seconds.
  9. The client knows it needs to add 45 seconds to its clock. This is done by subtracting 165 - 120 = 45 seconds where 45 seconds is the difference between the client and the server clock to which the client will set forward its clock by 45 seconds. This indication will be given in the drift file in PPM - Parts Per Million.

TIPS:

  • If the iburst parameters are removed, communication between the server will 8 times faster.
  • You can also increase the verbosity of the command chronyc sources by adding the parameter -v to it and detailed explanation of the values will be given i.e; chronyc source -v
  • You can pick up different NTP servers from the NIST website and restart the NTP service (chronyd).
  • NTP was invented by David L. Mills in 1981 and it is based on Marzullo's algorithm to get accurate time from several sources.
  • Timestamps of NTP are stored in seconds and it is 64 bit in size - 32 bit for number of seconds and 32 bit for fraction of seconds.
  • Number in drift file is measured in PPM - Parts per million
  • Offset - The difference in timestamps between the client and the server
  • Burst - The speed of communication between NTP client and NTP server will be 8 times more if "burst" is used.
  • The drift value is in PPM - Parts Per Million.
  • To convert into PPM is easy. Since we have 86,400 seconds in a day, therefore, 86,400 / 1,000,000 = 0.0864 PPM
  • If my drift file shows a value of Z  where Z = 30.3 simply do (30.3 x 0.0864) to get the drift file into milliseconds.