From 0225e4f1d7a9b900d5da838b953102c5d17090a4 Mon Sep 17 00:00:00 2001 From: otto <> Date: Sun, 9 Jun 2019 08:40:54 +0000 Subject: [PATCH] Introducing autmatic settime mode: if some preconditions are met (booting, constraint(s) defined) set the time but only if the clock should be moved forward by more than a minute, based on ntp replies that satisfied the constraints. Tested by many; ok deraadt@ --- src/usr.sbin/ntpd/client.c | 58 +++++++++++++++++++++++++++++++--- src/usr.sbin/ntpd/constraint.c | 9 ++++-- src/usr.sbin/ntpd/ntp.c | 4 +-- src/usr.sbin/ntpd/ntpd.c | 25 +++++++++++++-- src/usr.sbin/ntpd/ntpd.h | 10 ++++-- 5 files changed, 92 insertions(+), 14 deletions(-) diff --git a/src/usr.sbin/ntpd/client.c b/src/usr.sbin/ntpd/client.c index 476a804f..990d34b0 100644 --- a/src/usr.sbin/ntpd/client.c +++ b/src/usr.sbin/ntpd/client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: client.c,v 1.106 2019/05/29 18:48:33 otto Exp $ */ +/* $OpenBSD: client.c,v 1.107 2019/06/09 08:40:54 otto Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -29,6 +29,8 @@ #include "ntpd.h" int client_update(struct ntp_peer *); +int auto_cmp(const void *, const void *); +void handle_auto(double); void set_deadline(struct ntp_peer *, time_t); void @@ -213,7 +215,47 @@ client_query(struct ntp_peer *p) } int -client_dispatch(struct ntp_peer *p, u_int8_t settime) +auto_cmp(const void *a, const void *b) +{ + double at = *(const double *)a; + double bt = *(const double *)b; + return at < bt ? -1 : (at > bt ? 1 : 0); +} + +void +handle_auto(double offset) +{ + static int count; + static double v[AUTO_REPLIES]; + + /* + * It happens the (constraint) resolves initially fail, don't give up + * but see if we get validatd replies later. + */ + if (conf->constraint_median == 0) + return; + + if (offset < AUTO_THRESHOLD) { + /* don't bother */ + priv_settime(0); + return; + } + /* collect some more */ + v[count++] = offset; + if (count < AUTO_REPLIES) + return; + + /* we have enough */ + qsort(v, count, sizeof(double), auto_cmp); + if (AUTO_REPLIES % 2 == 0) + offset = (v[AUTO_REPLIES / 2 - 1] + v[AUTO_REPLIES / 2]) / 2; + else + offset = v[AUTO_REPLIES / 2]; + priv_settime(offset); +} + +int +client_dispatch(struct ntp_peer *p, u_int8_t settime, u_int8_t automatic) { struct ntp_msg msg; struct msghdr somsg; @@ -385,7 +427,9 @@ client_dispatch(struct ntp_peer *p, u_int8_t settime) if (p->trustlevel < TRUSTLEVEL_PATHETIC) interval = scale_interval(INTERVAL_QUERY_PATHETIC); else if (p->trustlevel < TRUSTLEVEL_AGGRESSIVE) - interval = scale_interval(INTERVAL_QUERY_AGGRESSIVE); + interval = (conf->settime && conf->automatic) ? + INTERVAL_QUERY_ULTRA_VIOLENCE : + scale_interval(INTERVAL_QUERY_AGGRESSIVE); else interval = scale_interval(INTERVAL_QUERY_NORMAL); @@ -408,8 +452,12 @@ client_dispatch(struct ntp_peer *p, u_int8_t settime) (long long)interval); client_update(p); - if (settime) - priv_settime(p->reply[p->shift].offset); + if (settime) { + if (automatic) + handle_auto(p->reply[p->shift].offset); + else + priv_settime(p->reply[p->shift].offset); + } if (++p->shift >= OFFSET_ARRAY_SIZE) p->shift = 0; diff --git a/src/usr.sbin/ntpd/constraint.c b/src/usr.sbin/ntpd/constraint.c index 13c05f92..804d79a6 100644 --- a/src/usr.sbin/ntpd/constraint.c +++ b/src/usr.sbin/ntpd/constraint.c @@ -1,4 +1,4 @@ -/* $OpenBSD: constraint.c,v 1.44 2019/05/30 13:42:19 otto Exp $ */ +/* $OpenBSD: constraint.c,v 1.45 2019/06/09 08:40:54 otto Exp $ */ /* * Copyright (c) 2015 Reyk Floeter @@ -157,8 +157,11 @@ constraint_query(struct constraint *cstr) /* Proceed and query the time */ break; case STATE_DNS_TEMPFAIL: - /* Retry resolving the address */ - constraint_init(cstr); + if (now > cstr->last + CONSTRAINT_RETRY_INTERVAL) { + /* Retry resolving the address */ + constraint_init(cstr); + return 0; + } return (-1); case STATE_QUERY_SENT: if (cstr->last + CONSTRAINT_SCAN_TIMEOUT > now) { diff --git a/src/usr.sbin/ntpd/ntp.c b/src/usr.sbin/ntpd/ntp.c index 25670f84..e1052fab 100644 --- a/src/usr.sbin/ntpd/ntp.c +++ b/src/usr.sbin/ntpd/ntp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ntp.c,v 1.152 2019/05/30 13:42:19 otto Exp $ */ +/* $OpenBSD: ntp.c,v 1.153 2019/06/09 08:40:54 otto Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -394,7 +394,7 @@ ntp_main(struct ntpd_conf *nconf, struct passwd *pw, int argc, char **argv) if (pfd[j].revents & (POLLIN|POLLERR)) { nfds--; if (client_dispatch(idx2peer[j - idx_peers], - conf->settime) == -1) { + conf->settime, conf->automatic) == -1) { log_warn("pipe write error (settime)"); ntp_quit = 1; } diff --git a/src/usr.sbin/ntpd/ntpd.c b/src/usr.sbin/ntpd/ntpd.c index 44c4f72f..84117207 100644 --- a/src/usr.sbin/ntpd/ntpd.c +++ b/src/usr.sbin/ntpd/ntpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ntpd.c,v 1.120 2019/01/14 16:30:21 florian Exp $ */ +/* $OpenBSD: ntpd.c,v 1.121 2019/06/09 08:40:54 otto Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,7 @@ void sighdlr(int); __dead void usage(void); +int auto_preconditions(const struct ntpd_conf *); int main(int, char *[]); void check_child(void); int dispatch_imsg(struct ntpd_conf *, int, char **); @@ -102,6 +104,19 @@ usage(void) exit(1); } +int +auto_preconditions(const struct ntpd_conf *cnf) +{ + int mib[2] = { CTL_KERN, KERN_SECURELVL }; + int constraints, securelevel; + size_t sz = sizeof(int); + + if (sysctl(mib, 2, &securelevel, &sz, NULL, 0) < 0) + err(1, "sysctl"); + constraints = !TAILQ_EMPTY(&cnf->constraints); + return !cnf->settime && constraints && securelevel == 0; +} + #define POLL_MAX 8 #define PFD_PIPE 0 #define PFD_MAX 1 @@ -185,6 +200,10 @@ main(int argc, char *argv[]) if ((pw = getpwnam(NTPD_USER)) == NULL) errx(1, "unknown user %s", NTPD_USER); + lconf.automatic = auto_preconditions(&lconf); + if (lconf.automatic) + lconf.settime = 1; + if (pname != NULL) { /* Remove our proc arguments, so child doesn't need to. */ if (sanitize_argv(&argc0, &argv0) == -1) @@ -209,7 +228,6 @@ main(int argc, char *argv[]) if (setpriority(PRIO_PROCESS, 0, -20) == -1) warn("can't set priority"); - reset_adjtime(); if (!lconf.settime) { log_init(lconf.debug, LOG_DAEMON); @@ -495,6 +513,9 @@ ntpd_settime(double d) char buf[80]; time_t tval; + if (d == 0) + return; + if (gettimeofday(&curtime, NULL) == -1) { log_warn("gettimeofday"); return; diff --git a/src/usr.sbin/ntpd/ntpd.h b/src/usr.sbin/ntpd/ntpd.h index 031a647c..e7b52805 100644 --- a/src/usr.sbin/ntpd/ntpd.h +++ b/src/usr.sbin/ntpd/ntpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ntpd.h,v 1.140 2019/05/29 18:48:33 otto Exp $ */ +/* $OpenBSD: ntpd.h,v 1.141 2019/06/09 08:40:54 otto Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -43,6 +43,7 @@ #define INTERVAL_QUERY_NORMAL 30 /* sync to peers every n secs */ #define INTERVAL_QUERY_PATHETIC 60 #define INTERVAL_QUERY_AGGRESSIVE 5 +#define INTERVAL_QUERY_ULTRA_VIOLENCE 1 /* used at startup for auto */ #define TRUSTLEVEL_BADPEER 6 #define TRUSTLEVEL_PATHETIC 2 @@ -66,6 +67,9 @@ #define MAX_DISPLAY_WIDTH 80 /* max chars in ctl_show report line */ #define FILTER_ADJFREQ 0x01 /* set after doing adjfreq */ +#define AUTO_REPLIES 4 /* # of ntp replies we want for auto */ +#define AUTO_THRESHOLD 60 /* dont bother auto setting < this */ + #define SENSOR_DATA_MAXAGE (15*60) #define SENSOR_QUERY_INTERVAL 15 @@ -74,6 +78,7 @@ #define SENSOR_DEFAULT_REFID "HARD" #define CONSTRAINT_ERROR_MARGIN (4) +#define CONSTRAINT_RETRY_INTERVAL (15) #define CONSTRAINT_SCAN_INTERVAL (15*60) #define CONSTRAINT_SCAN_TIMEOUT (10) #define CONSTRAINT_MARGIN (2.0*60) @@ -228,6 +233,7 @@ struct ntpd_conf { int verbose; u_int8_t listen_all; u_int8_t settime; + u_int8_t automatic; u_int8_t noaction; u_int8_t filters; time_t constraint_last; @@ -349,7 +355,7 @@ int client_peer_init(struct ntp_peer *); int client_addr_init(struct ntp_peer *); int client_nextaddr(struct ntp_peer *); int client_query(struct ntp_peer *); -int client_dispatch(struct ntp_peer *, u_int8_t); +int client_dispatch(struct ntp_peer *, u_int8_t, u_int8_t); void client_log_error(struct ntp_peer *, const char *, int); void set_next(struct ntp_peer *, time_t);