On Fri, Jan 10, 2020 at 03:14:42PM +0100, Otto Moerbeek wrote:
> Hi,
>
> THe ntp protocol uses 32-bit unsigned timestamps counting seconds
> since 1900. That means that in 2036 the timestamp field will wrap.
> This difff makes sure ntpd handles that correctly by assuming we are
> in era 0 unless we see "small" timestamps.
>
> tested in the future (incuding wrapping form era 0 to 1) on a couple
> of machines including one running xntpd for interoperability.
>
> ok?
ping...
-Otto
>
> Index: client.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ntpd/client.c,v
> retrieving revision 1.112
> diff -u -p -r1.112 client.c
> --- client.c 10 Nov 2019 19:24:47 -0000 1.112
> +++ client.c 10 Jan 2020 14:06:14 -0000
> @@ -324,12 +324,6 @@ client_dispatch(struct ntp_peer *p, u_in
> }
> }
>
> - if (T4 < JAN_1970) {
> - client_log_error(p, "recvmsg control format", EBADF);
> - set_next(p, error_interval());
> - return (0);
> - }
> -
> ntp_getmsg((struct sockaddr *)&p->addr->ss, buf, size, &msg);
>
> if (msg.orgtime.int_partl != p->query->msg.xmttime.int_partl ||
> @@ -374,16 +368,6 @@ client_dispatch(struct ntp_peer *p, u_in
> T1 = p->query->xmttime;
> T2 = lfp_to_d(msg.rectime);
> T3 = lfp_to_d(msg.xmttime);
> -
> - /*
> - * XXX workaround: time_t / tv_sec must never wrap.
> - * around 2020 we will need a solution (64bit time_t / tv_sec).
> - * consider every answer with a timestamp beyond january 2030 bogus.
> - */
> - if (T2 > JAN_2030 || T3 > JAN_2030) {
> - set_next(p, error_interval());
> - return (0);
> - }
>
> /* Detect liars */
> if (!p->trusted && conf->constraint_median != 0 &&
> Index: ntp.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ntpd/ntp.h,v
> retrieving revision 1.13
> diff -u -p -r1.13 ntp.h
> --- ntp.h 22 Apr 2009 07:42:17 -0000 1.13
> +++ ntp.h 10 Jan 2020 14:06:14 -0000
> @@ -141,7 +141,19 @@ struct ntp_query {
> #define MODE_RES2 7 /* reserved for private use */
>
> #define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
> -#define JAN_2030 1893456000UL + JAN_1970 /* 1. 1. 2030 00:00:00
> */
> +
> +/*
> + * The era we're in if we have no reason to assume otherwise.
> + * If lfp_to_d() sees an offset <= INT32_MAX the era is is assumed to be
> + * NTP_ERA + 1.
> + * Once the actual year is well into era 1, (after 2036) define NTP_ERA to 1
> + * and adapt (remove) the test in lfp_to_d().
> + * Once more than half of era 1 has elapsed (after 2104), re-inroduce the
> test
> + * to move to era 2 if offset <= INT32_MAX, repeat for each half era.
> + */
> +#define NTP_ERA 0
> +
> +#define SECS_IN_ERA (UINT32_MAX + 1ULL)
>
> #define NTP_VERSION 4
> #define NTP_MAXSTRATUM 15
> Index: util.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/ntpd/util.c,v
> retrieving revision 1.24
> diff -u -p -r1.24 util.c
> --- util.c 1 Mar 2017 00:56:30 -0000 1.24
> +++ util.c 10 Jan 2020 14:06:14 -0000
> @@ -86,12 +86,17 @@ d_to_tv(double d, struct timeval *tv)
> double
> lfp_to_d(struct l_fixedpt lfp)
> {
> - double ret;
> + double base, ret;
>
> lfp.int_partl = ntohl(lfp.int_partl);
> lfp.fractionl = ntohl(lfp.fractionl);
>
> - ret = (double)(lfp.int_partl) + ((double)lfp.fractionl / UINT_MAX);
> + /* see comment in ntp.h */
> + base = NTP_ERA;
> + if (lfp.int_partl <= INT32_MAX)
> + base++;
> + ret = base * SECS_IN_ERA;
> + ret += (double)(lfp.int_partl) + ((double)lfp.fractionl / UINT_MAX);
>
> return (ret);
> }
> @@ -101,6 +106,8 @@ d_to_lfp(double d)
> {
> struct l_fixedpt lfp;
>
> + while (d > SECS_IN_ERA)
> + d -= SECS_IN_ERA;
> lfp.int_partl = htonl((u_int32_t)d);
> lfp.fractionl = htonl((u_int32_t)((d - (u_int32_t)d) * UINT_MAX));
>
>
>