Dear Maintainer,
When DNS does not answer, "/etc/init.d/openntpd restart" (and
force-reload, which the if-up.d hook runs) can stop ntpd and not start
it again. After
that, "start" prints "Already running." and returns 0, but no ntpd runs.
Cause: stop and restart run
start-stop-daemon --stop --oknodo --quiet --retry=TERM/30/KILL/5
--user root --exec $DAEMON
which waits only for the root parent. The "dns engine" child runs as
_ntpd, and in my tests with DNS blocked it outlived the parent. The next
"start-stop-daemon --start" has no --user, finds the dns engine, starts
nothing and returns 1; restart exits 1 (set -e), which the if-up.d hook
ignores ("|| true"). "start" uses status_of_proc, which finds the dns
engine too. (#773569 added --retry to this line; --user root stayed.)
What I ran: a sid minbase chroot with openntpd 1:7.9p1-5 and the default
config, on a host running sysvinit (so no systemctl redirect), with the
host's own ntpd stopped. In a private mount namespace, the chroot's
/etc/resolv.conf pointed to 192.0.2.1 (TEST-NET-1); I did not trace
the lookups themselves. Each trial started ntpd as the init script does,
waited 3 or 18 s, ran "/etc/init.d/openntpd restart" and checked
2 s later. First trial (ps columns: pid, ppid, user, command):
before: 2898069 2898060 root /usr/sbin/ntpd -f
/etc/openntpd/ntpd.conf
2898071 2898069 _ntpd ntpd: ntp engine
2898072 2898071 _ntpd ntpd: dns engine
restart: rc=1, output "Restarting openntpd: "
after: 2898072 1 _ntpd ntpd: dns engine
ntpctl -s status: "ntpctl: connect: /run/openntpd/ntpd.sock:
Connection refused"
start: rc=0, output "Starting openntpd: Already running."; still
no ntpd
Results, 10 trials per version (5 single restarts, 5 pairs of concurrent
restarts):
- unpatched, 1:7.9p1-5 (sid) and 1:6.2p3-4.2+b1 (bookworm, same
setup without the chroot): 10 of 10 left only the dns engine running;
- patched as below, bookworm: 5 of 5 single restarts left one ntpd.
With working DNS, the unpatched script restarted correctly 30 of 30
times on bookworm.
Patch: drop --user root, so stop also waits for the _ntpd children.
--- a/debian/openntpd.init
+++ b/debian/openntpd.init
@@ -45,13 +45,13 @@
stop)
echo -n "Stopping $DESC: "
- start-stop-daemon --stop --oknodo --quiet --retry=TERM/30/KILL/5
--user root --exec $DAEMON
+ start-stop-daemon --stop --oknodo --quiet --retry=TERM/30/KILL/5
--exec $DAEMON
echo "$NAME."
;;
restart | force-reload)
echo -n "Restarting $DESC: "
- start-stop-daemon --stop --oknodo --quiet --retry=TERM/30/KILL/5
--user root --exec $DAEMON
+ start-stop-daemon --stop --oknodo --quiet --retry=TERM/30/KILL/5
--exec $DAEMON
start-stop-daemon --start --quiet --exec $DAEMON -- $DAEMON_OPTS
echo "$NAME."
;;
Costs of this patch, measured on bookworm only:
- Slow restart while DNS does not answer: 45 s, where the unpatched
restart returned at once. My hosts start ntpd with -s, which accounts
for at most 15 s, so the timing fits stop reaching the 30 s TERM timeout
and sending KILL; I did not trace the signals. The if-up.d hook runs
force-reload, so ifup waits as long (cf. #898159).
- Concurrent restarts: 3 of 5 pairs left TWO ntpd running. I now
serialize the script locally with flock(1), after PATH=:
LOCK=/run/openntpd.lock
(umask 077; : >>$LOCK)
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -o -w 120
$LOCK "$0" "$@" || :
With a lock, 14 of 14 pairs left one ntpd (3 on sid with these
lines, 11 on bookworm with earlier variants). I have seen concurrent
hook runs only with a locally modified hook, so the package may not need it.
Not tested: systemd. openntpd.service sets no KillMode, so the
default (control-group) should stop the dns engine too.
I found this because ntpd was found stopped on several of my
bookworm hosts after the if-up.d hook had restarted it. Slow DNS in
those cases is
unproven; the test above forces it.
I used AI assistants for the investigation and this draft; I carefully
reviewed the report.
Regards,
Teodor Milkov