From: Juergen Perlinger Date: Wed, 30 Mar 2016 17:28:04 +0000 (+0000) Subject: [Bug 3031] ntp broadcastclient unable to synchronize to an server when the time of... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=419ba58022921df105d4fb573008de4fb8137755;p=thirdparty%2Fntp.git [Bug 3031] ntp broadcastclient unable to synchronize to an server when the time of server changed. - Check the initial delay calculation and reject/unpeer the broadcast server if the delay exceeds the cutoff limit. (default 50ms) Retry again after the next broadcast packet. bk: 56fc0ca4-oKtZEsIKgTkzDu3mqUHRg --- diff --git a/ChangeLog b/ChangeLog index c70fe8fc5..c67a28f5e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,11 @@ * [Bug 2994] Systems with HAVE_SIGNALED_IO fail to compile. perlinger@ntp.org * [Bug 2995] Fixes to compile on Windows +* [Bug 3031] ntp broadcastclient unable to synchronize to an server + when the time of server changed. perlinger@ntp.org + - Check the initial delay calculation and reject/unpeer the broadcast + server if the delay exceeds 50ms. Retry again after the next + broadcast packet. --- (4.2.8p6) 2016/01/20 Released by Harlan Stenn diff --git a/ntpd/ntp_io.c b/ntpd/ntp_io.c index 95229d6a7..8050bb3af 100644 --- a/ntpd/ntp_io.c +++ b/ntpd/ntp_io.c @@ -1013,8 +1013,8 @@ remove_interface( stoa(&ep->bcast), ep->ifnum, ep->name); close_and_delete_fd_from_list(ep->bfd); ep->bfd = INVALID_SOCKET; - ep->flags &= ~INT_BCASTOPEN; } + ep->flags &= ~INT_BCASTOPEN; ninterfaces--; mon_clearinterface(ep); @@ -2565,7 +2565,7 @@ io_setbclient(void) continue; /* Only IPv4 addresses are valid for broadcast */ - REQUIRE(IS_IPV4(&interf->sin)); + REQUIRE(IS_IPV4(&interf->bcast)); /* Do we already have the broadcast address open? */ if (interf->flags & INT_BCASTOPEN) { @@ -2593,13 +2593,31 @@ io_setbclient(void) msyslog(LOG_INFO, "Listen for broadcasts to %s on interface #%d %s", stoa(&interf->bcast), interf->ifnum, interf->name); - } else { - /* silently ignore EADDRINUSE as we probably opened - the socket already for an address in the same network */ - if (errno != EADDRINUSE) - msyslog(LOG_INFO, - "failed to listen for broadcasts to %s on interface #%d %s", - stoa(&interf->bcast), interf->ifnum, interf->name); + } else switch (errno) { + /* Silently ignore EADDRINUSE as we probably + * opened the socket already for an address in + * the same network */ + case EADDRINUSE: + /* Some systems cannot bind a socket to a broadcast + * address, as that is not a valid host address. */ + case EADDRNOTAVAIL: +# ifdef SYS_WINNT /*TODO: use for other systems, too? */ + /* avoid recurrence here -- if we already have a + * regular socket, it's quite useless to try this + * again. + */ + if (interf->fd != INVALID_SOCKET) { + interf->flags |= INT_BCASTOPEN; + nif++; + } +# endif + break; + + default: + msyslog(LOG_INFO, + "failed to listen for broadcasts to %s on interface #%d %s", + stoa(&interf->bcast), interf->ifnum, interf->name); + break; } } set_reuseaddr(0); @@ -2639,8 +2657,8 @@ io_unsetbclient(void) stoa(&ep->bcast), ep->ifnum, ep->name); close_and_delete_fd_from_list(ep->bfd); ep->bfd = INVALID_SOCKET; - ep->flags &= ~INT_BCASTOPEN; } + ep->flags &= ~INT_BCASTOPEN; } broadcast_client_enabled = ISC_FALSE; } diff --git a/ntpd/ntp_proto.c b/ntpd/ntp_proto.c index ad454099f..d757b5bf2 100644 --- a/ntpd/ntp_proto.c +++ b/ntpd/ntp_proto.c @@ -25,6 +25,11 @@ #include #endif +/*[Bug 3031] define automatic broadcastdelay cutoff preset */ +#ifndef BDELAY_DEFAULT +# define BDELAY_DEFAULT (-0.050) +#endif + /* * This macro defines the authentication state. If x is 1 authentication * is required; othewise it is optional. @@ -1144,7 +1149,7 @@ receive( /* * Determine whether to execute the initial volley. */ - if (sys_bdelay != 0) { + if (sys_bdelay > 0.0) { #ifdef AUTOKEY /* * If a two-way exchange is not possible, @@ -1339,7 +1344,7 @@ receive( } if ( (current_time - peer->timelastrec) - < (1 << pkt->ppoll)) { + < (1u << pkt->ppoll) - 1) { msyslog(LOG_INFO, "receive: broadcast packet from %s arrived after %ld, not %d seconds!", stoa(&rbufp->recv_srcadr), (current_time - peer->timelastrec), @@ -1958,6 +1963,9 @@ process_packet( peer->aorg = p_xmt; peer->borg = peer->dst; if (t34 < 0 || t34 > 1.) { + /* drop all if in the initial volley */ + if (FLAG_BC_VOL & peer->flags) + goto bcc_init_volley_fail; snprintf(statstr, sizeof(statstr), "offset %.6f delay %.6f", t21, t34); report_event(PEVNT_XERR, peer, statstr); @@ -1983,10 +1991,21 @@ process_packet( * between the unicast timestamp and the broadcast * timestamp. This works for both basic and interleaved * modes. + * [Bug 3031] Don't keep this peer when the delay + * calculation gives reason to suspect clock steps. + * This is assumed for delays > 50ms. */ if (FLAG_BC_VOL & peer->flags) { peer->flags &= ~FLAG_BC_VOL; peer->delay = fabs(peer->offset - p_offset) * 2; + DPRINTF(2, ("broadcast volley: initial delay=%.6f\n", + peer->delay)); + if (peer->delay > fabs(sys_bdelay)) { + bcc_init_volley_fail: + DPRINTF(2, ("%s", "broadcast volley: initial delay exceeds limit\n")); + unpeer(peer); + return; + } } p_del = peer->delay; p_offset += p_del / 2; @@ -4333,7 +4352,7 @@ init_proto(void) sys_survivors = 0; sys_manycastserver = 0; sys_bclient = 0; - sys_bdelay = 0; + sys_bdelay = BDELAY_DEFAULT; /*[Bug 3031] delay cutoff */ sys_authenticate = 1; sys_stattime = current_time; orphwait = current_time + sys_orphwait; @@ -4426,7 +4445,7 @@ proto_config( break; case PROTO_BROADDELAY: /* default broadcast delay (bdelay) */ - sys_bdelay = dvalue; + sys_bdelay = (dvalue ? dvalue : BDELAY_DEFAULT); break; case PROTO_CEILING: /* stratum ceiling (ceiling) */