Hi,

I am running ntpd as a client with three upstream servers.  Some
of them are not synchonized and report a time that is off by several
seconds.

The ntpd client code corrects both T1 and T4 with the current offset
returned by adjtime(2) from the kernel.  T1 is local time when the
NTP packet is sent and T4 when the response is received.  If between
these events a NTP reply from another server is received, it may
change the kernel offset with adjtime(2).  Then the calulation of
the client offset is done with different bases, the result is wrong
and the system time starts moving around.

So instead of correcting T1 and T4 individually at different events,
I correct their sum once.  This fixes my setup.

Error handling missing if there is no timestamp in the response.
As this should not happen in our kernel, fatal() is fine.

I have tested this bugfix together with more cleanup and refactoring,
but I will send a separate diff for that.

ok?

bluhm

Index: usr.sbin/ntpd/client.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/ntpd/client.c,v
retrieving revision 1.114
diff -u -p -r1.114 client.c
--- usr.sbin/ntpd/client.c      11 Sep 2020 07:09:41 -0000      1.114
+++ usr.sbin/ntpd/client.c      16 Mar 2021 12:30:23 -0000
@@ -208,7 +208,7 @@ client_query(struct ntp_peer *p)
 
        p->query->msg.xmttime.int_partl = arc4random();
        p->query->msg.xmttime.fractionl = arc4random();
-       p->query->xmttime = gettime_corrected();
+       p->query->xmttime = gettime();
 
        if (ntp_sendmsg(p->query->fd, NULL, &p->query->msg) == -1) {
                p->senderrors++;
@@ -295,7 +295,6 @@ client_dispatch(struct ntp_peer *p, u_in
        somsg.msg_control = cmsgbuf.buf;
        somsg.msg_controllen = sizeof(cmsgbuf.buf);
 
-       T4 = getoffset();
        if ((size = recvmsg(p->query->fd, &somsg, 0)) == -1) {
                if (errno == EHOSTUNREACH || errno == EHOSTDOWN ||
                    errno == ENETUNREACH || errno == ENETDOWN ||
@@ -325,10 +324,12 @@ client_dispatch(struct ntp_peer *p, u_in
                if (cmsg->cmsg_level == SOL_SOCKET &&
                    cmsg->cmsg_type == SCM_TIMESTAMP) {
                        memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
-                       T4 += gettime_from_timeval(&tv);
+                       T4 = gettime_from_timeval(&tv);
                        break;
                }
        }
+       if (cmsg == NULL)
+               fatal("SCM_TIMESTAMP");
 
        ntp_getmsg((struct sockaddr *)&p->addr->ss, buf, size, &msg);
 
@@ -384,7 +385,7 @@ client_dispatch(struct ntp_peer *p, u_in
                return (0);
        }
 
-       p->reply[p->shift].offset = ((T2 - T1) + (T3 - T4)) / 2;
+       p->reply[p->shift].offset = ((T2 - T1) + (T3 - T4)) / 2 - getoffset();
        p->reply[p->shift].delay = (T4 - T1) - (T3 - T2);
        p->reply[p->shift].status.stratum = msg.stratum;
        if (p->reply[p->shift].delay < 0) {

Reply via email to