zerosleeps

Since 2010

NTP pool mode

Recent versions of NTP include a “pool” automatic discovery mode, which can used neatly with the pool.ntp.org project. To use this mode, rather than defining multiple individual server associations in your NTP configuration, you use one pool definition instead:

pool pool.ntp.org

This single association declaration tells ntpd to make multiple DNS requests to pool.ntp.org, which results in associations for multiple participating servers. Check out the results of host pool.ntp.org to see the mechanism in action. ntpd also intelligently detects duplicate servers, and polls enough candidates to maintain accuracy in case any peers go rogue.

However, when changing /etc/ntp.conf/ on macOS Sierra I found that the pool association wasn’t working: ntpq -p would never show any real associations:

$ ntpq -pn
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
 pool.ntp.org    .POOL.          16 p    -   64    0    0.000    0.000   0.001

It turns out that Apple’s default NTP configuration needs a couple of tweaks to get this working. The first trick is knowing how to modify \etc\ntp.conf without the System Preferences GUI overwriting it. It turns out that adding a blank comment line to the file is enough - the GUI will only update the first line in the file, and leave everything else alone. Here’s an example:

server time.asia.apple.com.
#
pool pool.ntp.org

Line 1 is maintained by System Preferences, but line 3 and beyond is left alone thanks to the dividing comment. Easy.

Now, back to my initial problem: the pool declaration not having the expected result. It turns out that this is down to the restrict settings in ntp-restrict.conf. Here’s what an out-of-the-box copy of \etc\ntp-restrict.conf looks like in macOS 10.12.4:

# Access restrictions documented in ntp.conf(5) and
# http://support.ntp.org/bin/view/Support/AccessRestrictions
# Limit network machines to time queries only

restrict default kod nomodify notrap nopeer noquery
restrict -6 default kod nomodify notrap nopeer noquery

# localhost is unrestricted
restrict 127.0.0.1
restrict -6 ::1

includefile /private/etc/ntp.conf
includefile /private/etc/ntp_opendirectory.conf

Note the “nopeer” flags. Here’s what the NTP documentation has to say about this, emphasis mine:

Deny packets that might mobilize an association unless authenticated. This includes broadcast, symmetric-active and manycast server packets when a configured association does not exist. It also includes pool associations, so if you want to use servers from a pool directive and also want to use nopeer by default, you’ll want a “restrict source …” line as well that does not include the nopeer directive.

So there’s the answer: add a restrict source line somewhere in the configuration which relaxes the nopeer directive. Here’s my line:

restrict source nomodify notrap noquery

I figured that because of it’s use by System Preferences, \etc\ntp.conf is less likely to be overwritten by software updates than \etc\ntp-restrict.conf is, so I’ve added the new line to ntp.conf. But shrug. My final configuration can therefore be boiled down to this:

server time.asia.apple.com.
pool pool.ntp.org
restrict default limited kod nomodify notrap nopeer noquery
restrict -6 default limited kod nomodify notrap nopeer noquery
restrict source nomodify notrap noquery
restrict 127.0.0.1
restrict -6 ::1

(The “kod” flag is meaningless without the “limited” flag, so I’ve fixed that as well.)

I spent longer troubleshooting this than I would have liked, mainly because an identical NTP configuration on an up-to-date Debian server didn’t exhibit the same problem. It turns out that there was a change in NTP version 4.2.7 which resulted in the “nopeer” directive disabling pool associations. Debian currently uses version 4.2.6 of NTP, while macOS Sierra is 4.2.8. It was this section from a post to the NTP mailing list that finally set me off in the right direction:

“restrict source” establishes a prototype restriction automatically added for each association’s IP address. Previously using the pool interfered with some locked-down restriction scenarios because the IP addresses of the pool servers used for a given run of ntpd were not predictable, so the default restriction had to be loose enough to allow retrieving time. “restrict source” allows the operator to configure looser restrictions automatically applied to each association address and tighter “restrict default”.