s6-networking: the s6-sntpclock program
Keywords: s6-networking s6-sntpclock sntp clock sntpv4 client

s6-networking
Software
skarnet.org

# The `s6-sntpclock` program

`s6-sntpclock` is a small SNTP client. It connects to an SNTP or NTP server, computes an estimated discrepancy between the local clock time and the absolute time given by the server, and outputs it on stdout.

## Interface

         s6-sntpclock [ -f ] [ -v verbosity ] [ -r roundtrips ] [ -t triptimeout ] [ -h throttle ] [ -T totaltimeout ] [ -e errmax ] [ -p port ] ipaddress | s6-clockview

- s6-sntpclock exchanges SNTPv4 messages with a SNTP server listening on ipaddress, UDP port 123. ipaddress can be IPv4 or IPv6.
- It computes the mean difference between the absolute time given by the system clock and the one given by the server.
- It prints the difference to stdout in a format understood by s6-clockadd and s6-clockview. It then exits 0.

## Options

- `-f` : force. Normally, s6-sntpclock exits 111 if it cannot compute a time with a smaller uncertainty than errmax. If this option is set, it will output a time difference and exit 0 even if the error is too big.
- `-v verbosity` : be more or less verbose. By default, verbosity is 1. 0 means only print fatal error messages; 3 means trace every exchange with the server.
- `-r roundtrips` : perform roundtrips exchanges with the server. By default, roundtrips is 10. A lower value yields a higher time uncertainty; a higher value puts more load on the server.
- `-t triptimeout` : if a SNTP exchange with the server takes more than triptimeout milliseconds, abort this exchange and move on to the next one. By default, triptimeout is 2000.
- `-h throttle` : wait throttle milliseconds between exchanges with the server. A lower value gets the final result earlier, but exerts more load on the server. A higher value puts a lighter load on the server, but delays the computation. By default, throttle is 0. It is recommended to set it to a reasonable nonzero value when increasing roundtrips.
- `-T totaltimeout` : if the whole operation takes more than totaltimeout milliseconds, abort and exit 1. By default, totaltimeout is 10000.
- `-e errmax` : accept a maximum time uncertainty of errmax milliseconds. By default, errmax is 100.
- `-p port` : contact a server on port port. By default, port is 123.

## Notes

- There are a lot of infelicities in the NTP protocol (which SNTP is a subset of). The biggest offender is probably that NTP cannot handle a time difference of more than 34 years: if the time given by the NTP server is more than 34 years away from the time given by the system clock, then NTP just cannot compute. This is a problem for CMOS-less systems, where the system clock is initialized to the Unix Epoch. The solution is to first manually initialize the system clock with a program such as date or s6-clock to a closer time (such as 2013-01-01, which will be good up to 2047), then contact the NTP server.
- A less obvious problem with NTP is that it works with UTC time, which means that it gives inaccurate results when close to a leap second, up to one second off when used during a leap second, and this is bound to the use of UTC: there is nothing you can do about it. The only solution to get reliable results even around a leap second is to use linear time such as TAI; the s6-taiclock and s6-taiclockd programs provide tools to do so.

## A word on ntpd

From a Unix software engineering standpoint, the well-known ntpd program is an eldritch abomination. The main reason for it is that, just like its lovely cousin BIND, ntpd performs a lot of different tasks in a unique process, instead of separating what could, and should, be separated. This is confusing for both the programmer and the software user.

- The term "NTP server" means two different things:
  - A program that serves NTP time to the Internet and can be accessed by NTP clients.
  - A daemon, i.e. a long-lived process, that runs on a machine and handles NTP-related stuff such as keeping the system clock accurate.
  The former is the real meaning of "NTP server". The latter is a common usage for the term, but comes from a misuse of "server" to mean "daemon". ntpd does not help clear the misunderstanding since it does both. It acts as an NTP server, and as an NTP client getting its time from lower-strata NTP servers, and as a local system clock management daemon. Those are already 3 separate tasks.
- Local system clock management itself involves several duties. There is the regular setting of the system clock, which can be done with a loop over a simple program such as s6-clockadd. There is also control of the clock skew, which s6-networking does not provide because there is no portable interface for that; there is such a tool in the clockspeed package.
- ntpd includes a complete cryptographic key management system for the crypto part of NTP. NTP is not the only protocol that uses cryptography and asymmetric keys; managing keys in a separate tool, not in the NTP daemon itself, would be simpler and smarter.
- ntpd provides monitoring support for client and server timekeeping performance. This would be best implemented as a separate specific log analyzing tool.

And of course, no matter how many layers of complexity you add onto ntpd, it will never be able to give accurate time in the vicinity of a leap second, since the very protocol is flawed by design - but the ntpd authors cannot be blamed for that. Also, the ntpd writers, not the designers, should be praised: the history of ntpd security flaws is remarkably small, which is quite a feat for a huge monolithic root daemon.

Network synchronization is important, NTP has its perks and valid use cases, and its existence is a good thing. However, I wish that the main NTP implementation weren't written as a big fat clumsy process running as root. s6-sntpclock together with s6-clockadd aims to provide a small, simple tool to keep system clocks, especially in embedded devices, synchronized to a NTP server.