1

I installed ntpd on my Debian host machine to keep the hardware RTC "up-to-date". By sharing the system's clock the time gets automatically propagated to all installed containers (lxc). One of those containers runs my router.

I'd like to use this router to propagate its time to all interested devices in my networks, so they don't need an internet connection by themselves. I don't want to use the host as server (hopefully disabled by interface ignore all).

How can I install and configure a pure ntp-server in a container, which takes the system's clock as its only reference? It shall never set the clock by itself.

How can I install and configure a pure ntp-client, which doesn't accept incoming connections from other peers and leaks as few informations as possible?

Kai Giebeler
  • 263
  • 2
  • 7
  • Why not disable the host’s ntpd and use the container’s both to propagate time and to discipline the host’s clock? – user2233709 Oct 21 '17 at 00:03
  • This would require to extend the container's permission to update the clock which I try to avoid for an Internet gateway for security reasons. – Kai Giebeler Oct 22 '17 at 01:36
  • Given that you’re using ntpd to discipline your system clock, probably from external servers, I’d rather run that ntpd in a container (even with extended capabilities) than on the host. – user2233709 Oct 22 '17 at 09:59

2 Answers2

2

The configuration of NTP deviates from what I'd call intuitive. It installs, by default, a client which reads and writes the system's clock and starts listening on all interfaces and bridges and eagerly uses them to provide informations about its status without authentication.

I had a hard time gathering all informations and documentation to get this (hopefully) right. Even the default configuration file contained several statements that aren't covered by the man-pages.

The following configuration seems to work fine without providing excessive informations and services.

This is the configuration to be installed on the host machine to enforce a client-only operation:

>> my-host:/etc/ntp.conf

# stop listening for incoming connections an all interfaces including 0.0.0.0 and [::]
interface ignore all
interface ignore wildcard

# only allow listening on the interface used to contact the time servers
interface listen 10.2.20.2

# your pools or servers
pool 0.debian.pool.ntp.org iburst
pool 1.debian.pool.ntp.org iburst
pool 2.debian.pool.ntp.org iburst
pool 3.debian.pool.ntp.org iburst

# by default drop all incoming connections on all interfaces
restrict default ignore

# unrestriced control for local connections
restrict 127.0.0.1
restrict ::1

# Needed for adding pool entries
restrict source notrap nomodify noquery

Restarting the service gives us a comprehensible list of listening sockets. (my-host:ntp cannot be avoided because of the way NTPd works.)

my-host:# netstat -a|grep ntp
udp        0      0 my-host:ntp   0.0.0.0:*
udp        0      0 localhost:ntp 0.0.0.0:*
udp6       0      0 localhost:ntp [::]:*

This is the configuration to be installed on the router-container to enforce a server-only operation (backed by the system's clock as source of time, thanks to @BillThor):

>> router:/etc/ntp.conf

# don't update the system's clock
disable kernel

# local clock as preferred and only source
server 127.127.1.0 prefer

# stop listening for incoming connections an all interfaces including 0.0.0.0 and [::]
interface ignore all
interface ignore wildcard

# whitelist addresses to listen on for NTP clients
interface listen 10.1.2.1
interface listen 10.2.2.2
interface listen 10.3.2.3
interface listen 10.4.2.4
interface listen 10.5.2.5

# set "serve" as the only permission given to all listening interfaces per default
restrict default kod notrap nomodify nopeer noquery limited

# unrestriced control for local connections
restrict 127.0.0.1
restrict ::1

# broadcast time (optional)
broadcast 10.1.255.255
broadcast 10.2.255.255
broadcast 10.3.255.255
broadcast 10.4.255.255
broadcast 10.5.255.255

Restarting the service gives us the local clock as preferred source and a list of (optional) broadcast targets

router:# ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*LOCAL(0)        .LOCL.           5 l   16   64    3    0.000    0.000   0.000
 10.1.255.255    .BCST.          16 B    -   64    0    0.000    0.000   0.000
 10.2.255.255    .BCST.          16 B    -   64    0    0.000    0.000   0.000
 10.3.255.255    .BCST.          16 B    -   64    0    0.000    0.000   0.000
 10.4.255.255    .BCST.          16 B    -   64    0    0.000    0.000   0.000
 10.5.255.255    .BCST.          16 B    -   64    0    0.000    0.000   0.000

... and a comprehensible list of listening sockets to serve the local network.

router:# netstat -a|grep ntp
udp        0      0 router-lan5:ntp 0.0.0.0:*
udp        0      0 router-lan4:ntp 0.0.0.0:*
udp        0      0 router-lan3:ntp 0.0.0.0:*
udp        0      0 router-lan2:ntp 0.0.0.0:*
udp        0      0 router-lan1:ntp 0.0.0.0:*
udp        0      0 localhost:ntp   0.0.0.0:*
udp6       0      0 localhost:ntp   [::]:*

The disable kernel (thanks to @PaulGear) prohibits the daemon from setting the system's clock which isn't allowed within a typical container. Otherwise it floods the log with:

ntpd[1568]: adj_systime: Operation not permitted

On startup there are still some harmless glitches, I don't know how to get rid of:

ntpd[1568]: start_kern_loop: ntp_loopfilter.c line 1119: ntp_adjtime: Operation not permitted
ntpd[1568]: set_freq: ntp_loopfilter.c line 1082: ntp_adjtime: Operation not permitted
Kai Giebeler
  • 263
  • 2
  • 7
  • 1
    I think in the case of what you're trying to do, you probably shouldn't fudge the local clock to stratum 10, but to whatever stratum the host ends up at. Generally using the local clock and fudging the stratum is not recommended, but it makes sense in your use case. – Paul Gear Oct 21 '17 at 03:39
  • Thanks, you're right; it should derive the value from whatever the host uses as source (+1); which would be a stratum of 2-3 in my case. However: I just tried removing the fudge and ended up with a good-enough stratum of 5 (which might be the default for a local source). I'm gonna update my answer. – Kai Giebeler Oct 22 '17 at 01:30
1

Just add the local clock as the server and disable all servers. Fudge the priority so if anyone includes your host as a server they don't think you are running and atomic clock. This is the configuration I use for my servers:

# Fallback to local clock if all else fails
server  127.127.1.0     # local clock
fudge   127.127.1.0 stratum 10

To prevent serving time use a restrict clause.

restrict 192.168.0.0    mask 255.255.0.0     notrap nomodify nopeer noserve

Documentation is at ntp.org.

BillThor
  • 27,737
  • 3
  • 37
  • 69
  • 1
    You'll also need `disable kernel` so that the container doesn't attempt to discipline the local clock (which is being handled by ntpd on the host). – Paul Gear Oct 19 '17 at 00:43
  • I fixed a "strata too high"-error by adding `prefer` to the local clock in the router's configuration. For the host: The `restrict` statement didn't block queries so I added `noquery` to the list. But it still listens on all ~20 interfaces though it shall not provide any service to any other client. @PaulGear Thanks adding your hint! I forgot to mention this problem in my question. I'll update my question and provide an answer summing up all parts. – Kai Giebeler Oct 20 '17 at 20:21