diff options
author | roberto <roberto@FreeBSD.org> | 2008-08-22 15:58:00 +0000 |
---|---|---|
committer | roberto <roberto@FreeBSD.org> | 2008-08-22 15:58:00 +0000 |
commit | b85c7169a740b2edf0106ad59fdaa1b0160f823c (patch) | |
tree | 2b9fb7f64eacb322e95695e412c923e97ba33e88 /contrib/ntp/ntpd/ntp_proto.c | |
parent | 1d197cfe9feac6bc29537d8e53c30b6435937b95 (diff) | |
parent | 7a6072eb585696f8856cd498c3fd194cf49f14c6 (diff) | |
download | FreeBSD-src-b85c7169a740b2edf0106ad59fdaa1b0160f823c.zip FreeBSD-src-b85c7169a740b2edf0106ad59fdaa1b0160f823c.tar.gz |
Merge ntpd & friends 4.2.4p5 from vendor/ntp/dist into head. Next commit
will update usr.sbin/ntp to match this.
MFC after: 2 weeks
Diffstat (limited to 'contrib/ntp/ntpd/ntp_proto.c')
-rw-r--r-- | contrib/ntp/ntpd/ntp_proto.c | 2672 |
1 files changed, 1457 insertions, 1215 deletions
diff --git a/contrib/ntp/ntpd/ntp_proto.c b/contrib/ntp/ntpd/ntp_proto.c index 451bc9a..0ab2498 100644 --- a/contrib/ntp/ntpd/ntp_proto.c +++ b/contrib/ntp/ntpd/ntp_proto.c @@ -25,19 +25,26 @@ #endif /* + * This macro defines the authentication state. If x is 1 authentication + * is required; othewise it is optional. + */ +#define AUTH(x, y) ((x) ? (y) == AUTH_OK : (y) == AUTH_OK || \ + (y) == AUTH_NONE) + +/* * System variables are declared here. See Section 3.2 of the * specification. */ u_char sys_leap; /* system leap indicator */ u_char sys_stratum; /* stratum of system */ -s_char sys_precision; /* local clock precision */ +s_char sys_precision; /* local clock precision (log2 s) */ double sys_rootdelay; /* roundtrip delay to primary source */ double sys_rootdispersion; /* dispersion to primary source */ -u_int32 sys_refid; /* reference source for local clock */ -u_int32 sys_peer_refid; /* hashed refid of our current peer */ +u_int32 sys_refid; /* source/loop in network byte order */ static double sys_offset; /* current local clock offset */ l_fp sys_reftime; /* time we were last updated */ struct peer *sys_peer; /* our current peer */ +struct peer *sys_pps; /* our PPS peer */ struct peer *sys_prefer; /* our cherished peer */ int sys_kod; /* kod credit */ int sys_kod_rate = 2; /* max kod packets per second */ @@ -54,9 +61,12 @@ int sys_calldelay; /* modem callup delay (s) */ int sys_authenticate; /* requre authentication for config */ l_fp sys_authdelay; /* authentication delay */ static u_long sys_authdly[2]; /* authentication delay shift reg */ -static u_char leap_consensus; /* consensus of survivor leap bits */ -static double sys_selerr; /* select error (squares) */ -static double sys_syserr; /* system error (squares) */ +static double sys_mindisp = MINDISPERSE; /* min disp increment (s) */ +static double sys_maxdist = MAXDISTANCE; /* selection threshold (s) */ +double sys_jitter; /* system jitter (s) */ +static int sys_hopper; /* anticlockhop counter */ +static int sys_maxhop = MAXHOP; /* anticlockhop counter threshold */ +int leap_next; /* leap consensus */ keyid_t sys_private; /* private value for session seed */ int sys_manycastserver; /* respond to manycast client pkts */ int peer_ntpdate; /* active peers in ntpdate mode */ @@ -68,11 +78,15 @@ char *sys_hostname; /* gethostname() name */ /* * TOS and multicast mapping stuff */ -int sys_floor = 1; /* cluster stratum floor */ -int sys_ceiling = STRATUM_UNSPEC; /* cluster stratum ceiling*/ +int sys_floor = 0; /* cluster stratum floor */ +int sys_ceiling = STRATUM_UNSPEC; /* cluster stratum ceiling */ int sys_minsane = 1; /* minimum candidates */ int sys_minclock = NTP_MINCLOCK; /* minimum survivors */ +int sys_maxclock = NTP_MAXCLOCK; /* maximum candidates */ int sys_cohort = 0; /* cohort switch */ +int sys_orphan = STRATUM_UNSPEC + 1; /* orphan stratum */ +double sys_orphandelay = 0; /* orphan root delay */ +int sys_beacon = BEACON; /* manycast beacon interval */ int sys_ttlmax; /* max ttl mapping vector index */ u_char sys_ttl[MAX_TTL]; /* ttl mapping vector */ @@ -91,13 +105,15 @@ u_long sys_badauth; /* bad authentication */ u_long sys_limitrejected; /* rate exceeded */ static double root_distance P((struct peer *)); -static double clock_combine P((struct peer **, int)); +static void clock_combine P((struct peer **, int)); static void peer_xmit P((struct peer *)); -static void fast_xmit P((struct recvbuf *, int, keyid_t, int)); +static void fast_xmit P((struct recvbuf *, int, keyid_t, + int)); static void clock_update P((void)); -int default_get_precision P((void)); +static int default_get_precision P((void)); static int peer_unfit P((struct peer *)); + /* * transmit - Transmit Procedure. See Section 3.4.2 of the * specification. @@ -109,193 +125,199 @@ transmit( { int hpoll; - /* * The polling state machine. There are two kinds of machines, * those that never expect a reply (broadcast and manycast * server modes) and those that do (all other modes). The dance * is intricate... */ + /* + * Orphan mode is active when enabled and when no servers less + * than the orphan statum are available. In this mode packets + * are sent at the orphan stratum. An orphan with no other + * synchronization source is an orphan parent. It assumes root + * delay zero and reference ID the loopback address. All others + * are orphan children with root delay randomized over a 1-s + * range. The root delay is used by the election algorithm to + * select the order of synchronization. + */ hpoll = peer->hpoll; + if (sys_orphan < STRATUM_UNSPEC && sys_peer == NULL) { + sys_leap = LEAP_NOWARNING; + sys_stratum = sys_orphan; + sys_refid = htonl(LOOPBACKADR); + sys_rootdelay = 0; + sys_rootdispersion = 0; + } + + /* + * In broadcast mode the poll interval is never changed from + * minpoll. + */ if (peer->cast_flags & (MDF_BCAST | MDF_MCAST)) { + peer->outdate = current_time; + peer_xmit(peer); + poll_update(peer, hpoll); + return; + } - /* - * In broadcast mode the poll interval is fixed - * at minpoll. - */ - hpoll = peer->minpoll; - } else if (peer->cast_flags & MDF_ACAST) { + /* + * In manycast mode we start with unity ttl. The ttl is + * increased by one for each poll until either sys_maxclock + * servers have been found or the maximum ttl is reached. When + * sys_maxclock servers are found we stop polling until one or + * more servers have timed out or until less than minpoll + * associations turn up. In this case additional better servers + * are dragged in and preempt the existing ones. + */ + if (peer->cast_flags & MDF_ACAST) { + peer->outdate = current_time; + if (peer->unreach > sys_beacon) { + peer->unreach = 0; + peer->ttl = 0; + peer_xmit(peer); + } else if (sys_survivors < sys_minclock || + peer_preempt < sys_maxclock) { + if (peer->ttl < sys_ttlmax) + peer->ttl++; + peer_xmit(peer); + } + peer->unreach++; + poll_update(peer, hpoll); + return; + } - /* - * In manycast mode we start with the minpoll interval - * and ttl. However, the actual poll interval is eight - * times the nominal poll interval shown here. If fewer - * than sys_minclock servers are found, the ttl is - * increased by one and we try again. If this continues - * to the max ttl, the poll interval is bumped by one - * and we try again. If at least sys_minclock servers - * are found, the poll interval increases with the - * system poll interval to the max and we continue - * indefinately. However, about once per day when the - * agreement parameters are refreshed, the manycast - * clients are reset and we start from the beginning. - * This is to catch and clamp the ttl to the lowest - * practical value and avoid knocking on spurious doors. - */ - if (sys_survivors < sys_minclock && peer->ttl < - sys_ttlmax) - peer->ttl++; - hpoll = sys_poll; - } else { + /* + * In unicast modes the dance is much more intricate. It is + * desigmed to back off whenever possible to minimize network + * traffic. + */ + if (peer->burst == 0) { + u_char oreach; /* - * For associations expecting a reply, the watchdog - * counter is bumped by one if the peer has not been - * heard since the previous poll. If the counter reaches - * the max, the poll interval is doubled and the peer is - * demobilized if not configured. + * Update the reachability status. If not heard for + * three consecutive polls, stuff infinity in the clock + * filter. */ - peer->unreach++; - if (peer->unreach >= NTP_UNREACH) { - hpoll++; - if (peer->flags & FLAG_CONFIG) { + oreach = peer->reach; + peer->outdate = current_time; + if (peer == sys_peer) + sys_hopper++; + peer->reach <<= 1; + if (!(peer->reach & 0x07)) + clock_filter(peer, 0., 0., MAXDISPERSE); + if (!peer->reach) { - /* - * If nothing is likely to change in - * future, flash the access denied bit - * so we won't bother the dude again. - */ - if (memcmp((char *)&peer->refid, - "DENY", 4) == 0 || - memcmp((char *)&peer->refid, - "CRYP", 4) == 0) - peer->flash |= TEST4; - } else { - unpeer(peer); - return; + /* + * Here the peer is unreachable. If it was + * previously reachable, raise a trap. + */ + if (oreach) { + report_event(EVNT_UNREACH, peer); + peer->timereachable = current_time; } - } - if (peer->burst == 0) { - u_char oreach; - oreach = peer->reach; - peer->reach <<= 1; - peer->hyst *= HYST_TC; - if (peer->reach == 0) { - - /* - * If this association has become - * unreachable, clear it and raise a - * trap. - */ - if (oreach != 0) { - report_event(EVNT_UNREACH, - peer); - peer->timereachable = - current_time; - if (peer->flags & FLAG_CONFIG) { - peer_clear(peer, - "INIT"); - } else { - unpeer(peer); - return; - } - } - if (peer->flags & FLAG_IBURST) - peer->burst = NTP_BURST; - } else { - /* - * Here the peer is reachable. If it has - * not been heard for three consecutive - * polls, stuff the clock filter. Next, - * determine the poll interval. If the - * peer is unfit for synchronization, - * increase it by one; otherwise, use - * the system poll interval. - */ - if (!(peer->reach & 0x07)) { - clock_filter(peer, 0., 0., - MAXDISPERSE); - clock_select(); - } - if (peer_unfit(peer)) - hpoll++; - else - hpoll = sys_poll; - if (peer->flags & FLAG_BURST) - peer->burst = NTP_BURST; + /* + * Send a burst if enabled, but only once after + * a peer becomes unreachable. If the prempt + * flag is dim, bump the unreach counter by one; + * otherwise, bump it by three. + */ + if (peer->flags & FLAG_IBURST && + peer->unreach == 0) { + peer->burst = NTP_BURST; } + if (!(peer->flags & FLAG_PREEMPT)) + peer->unreach++; + else + peer->unreach += 3; } else { /* - * Source rate control. If we are restrained, - * each burst consists of only one packet. + * Here the peer is reachable. Set the poll + * interval to the system poll interval. Send a + * burst only if enabled and the peer is fit. + * + * Respond to the peer evaluation produced by + * the selection algorithm. If less than the + * outlyer level, up the unreach by three. If + * there are excess associations, up the unreach + * by two if not a candidate and by one if so. */ - if (memcmp((char *)&peer->refid, "RSTR", 4) == - 0) - peer->burst = 0; - else - peer->burst--; - if (peer->burst == 0) { - /* - * If a broadcast client at this point, - * the burst has concluded, so we switch - * to client mode and purge the keylist, - * since no further transmissions will - * be made. - */ - if (peer->cast_flags & MDF_BCLNT) { - peer->hmode = MODE_BCLIENT; + if (!(peer->flags & FLAG_PREEMPT)) { + peer->unreach = 0; + } else if (peer->status < CTL_PST_SEL_SELCAND) { + peer->unreach += 3; + } else if (peer_preempt > sys_maxclock) { + if (peer->status < CTL_PST_SEL_SYNCCAND) + peer->unreach += 2; + else + peer->unreach++; + } else { + peer->unreach = 0; + } + hpoll = sys_poll; + if (peer->flags & FLAG_BURST && + !peer_unfit(peer)) + peer->burst = NTP_BURST; + } + + /* + * Watch for timeout. If ephemeral or preemptable, toss + * the rascal; otherwise, bump the poll interval. + */ + if (peer->unreach >= NTP_UNREACH) { + if (peer->flags & FLAG_PREEMPT || + !(peer->flags & FLAG_CONFIG)) { + peer_clear(peer, "TIME"); + unpeer(peer); + return; + } else { + hpoll++; + } + } + } else { + peer->burst--; + + /* + * If a broadcast client at this point, the burst has + * concluded, so we switch to client mode and purge the + * keylist, since no further transmissions will be made. + */ + if (peer->burst == 0) { + if (peer->cast_flags & MDF_BCLNT) { + peer->hmode = MODE_BCLIENT; #ifdef OPENSSL - key_expire(peer); + key_expire(peer); #endif /* OPENSSL */ - } - poll_update(peer, hpoll); - clock_select(); + } - /* - * If ntpdate mode and the clock has not - * been set and all peers have completed - * the burst, we declare a successful - * failure. - */ - if (mode_ntpdate) { - peer_ntpdate--; - if (peer_ntpdate > 0) { - poll_update( - peer, hpoll); - return; - } + /* + * If ntpdate mode and the clock has not been + * set and all peers have completed the burst, + * we declare a successful failure. + */ + if (mode_ntpdate) { + peer_ntpdate--; + if (peer_ntpdate == 0) { msyslog(LOG_NOTICE, "no reply; clock not set"); exit (0); } - poll_update(peer, hpoll); - return; } } } - peer->outdate = current_time; /* - * Do not transmit if in broadcast cclient mode or access has - * been denied. + * Do not transmit if in broadcast client mode. */ - if (peer->hmode == MODE_BCLIENT || peer->flash & TEST4) { - poll_update(peer, hpoll); - return; - - /* - * Do not transmit in broadcast mode unless we are synchronized. - */ - } else if (peer->hmode == MODE_BROADCAST && sys_peer == NULL) { - poll_update(peer, hpoll); - return; - } - peer_xmit(peer); + if (peer->hmode != MODE_BCLIENT) + peer_xmit(peer); poll_update(peer, hpoll); } + /* * receive - Receive Procedure. See section 3.4.3 in the specification. */ @@ -306,15 +328,19 @@ receive( { register struct peer *peer; /* peer structure pointer */ register struct pkt *pkt; /* receive packet pointer */ + int hisversion; /* packet version */ + int hisleap; /* packet leap indicator */ int hismode; /* packet mode */ + int hisstratum; /* packet stratum */ int restrict_mask; /* restrict bits */ int has_mac; /* length of MAC field */ int authlen; /* offset of MAC field */ - int is_authentic; /* cryptosum ok */ + int is_authentic = 0; /* cryptosum ok */ keyid_t skeyid = 0; /* key ID */ struct sockaddr_storage *dstadr_sin; /* active runway */ struct peer *peer2; /* aux peer structure pointer */ - l_fp p_org; /* originate timestamp */ + l_fp p_org; /* origin timestamp */ + l_fp p_rec; /* receive timestamp */ l_fp p_xmt; /* transmit timestamp */ #ifdef OPENSSL keyid_t tkeyid = 0; /* temporary key ID */ @@ -323,6 +349,7 @@ receive( int rval; /* cookie snatcher */ #endif /* OPENSSL */ int retcode = AM_NOMATCH; + int at_listhead; /* * Monitor the packet and get restrictions. Note that the packet @@ -343,20 +370,24 @@ receive( sys_badlength++; return; /* bogus port */ } - ntp_monitor(rbufp); - restrict_mask = restrictions(&rbufp->recv_srcadr); + at_listhead = ntp_monitor(rbufp); + restrict_mask = restrictions(&rbufp->recv_srcadr, at_listhead); #ifdef DEBUG if (debug > 1) - printf("receive: at %ld %s<-%s restrict %03x\n", + printf("receive: at %ld %s<-%s flags %x restrict %03x\n", current_time, stoa(&rbufp->dstadr->sin), - stoa(&rbufp->recv_srcadr), restrict_mask); + stoa(&rbufp->recv_srcadr), + rbufp->dstadr->flags, restrict_mask); #endif if (restrict_mask & RES_IGNORE) { sys_restricted++; - return; /* no anything */ + return; /* ignore everything */ } pkt = &rbufp->recv_pkt; + hisversion = PKT_VERSION(pkt->li_vn_mode); + hisleap = PKT_LEAP(pkt->li_vn_mode); hismode = (int)PKT_MODE(pkt->li_vn_mode); + hisstratum = PKT_TO_STRATUM(pkt->stratum); if (hismode == MODE_PRIVATE) { if (restrict_mask & RES_NOQUERY) { sys_restricted++; @@ -387,10 +418,10 @@ receive( * Version check must be after the query packets, since they * intentionally use early version. */ - if (PKT_VERSION(pkt->li_vn_mode) == NTP_VERSION) { + if (hisversion == NTP_VERSION) { sys_newversionpkt++; /* new version */ - } else if (!(restrict_mask & RES_VERSION) && - PKT_VERSION(pkt->li_vn_mode) >= NTP_OLDVERSION) { + } else if (!(restrict_mask & RES_VERSION) && hisversion >= + NTP_OLDVERSION) { sys_oldversionpkt++; /* previous version */ } else { sys_unknownversion++; @@ -404,7 +435,7 @@ receive( * would interpret as client mode. */ if (hismode == MODE_UNSPEC) { - if (PKT_VERSION(pkt->li_vn_mode) == NTP_OLDVERSION) { + if (hisversion == NTP_OLDVERSION) { hismode = MODE_CLIENT; } else { sys_badlength++; @@ -413,35 +444,15 @@ receive( } /* - * Discard broadcast if not enabled as broadcast client. If - * Autokey, the wildcard interface cannot be used, so dump - * packets gettiing off the bus at that stop as well. This means - * that some systems with broken interface code, specifically - * Linux, will not work with Autokey. - */ - if (hismode == MODE_BROADCAST) { - if (!sys_bclient || restrict_mask & RES_NOPEER) { - sys_restricted++; - return; /* no client */ - } -#ifdef OPENSSL - if (crypto_flags && rbufp->dstadr == any_interface) { - sys_restricted++; - return; /* no client */ - } -#endif /* OPENSSL */ - } - - /* * Parse the extension field if present. We figure out whether * an extension field is present by measuring the MAC size. If - * the number of words following the packet header is 0 or 1, no - * MAC is present and the packet is not authenticated. If 1, the - * packet is a reply to a previous request that failed to - * authenticate. If 3, the packet is authenticated with DES; if - * 5, the packet is authenticated with MD5. If greater than 5, - * an extension field is present. If 2 or 4, the packet is a - * runt and goes poof! with a brilliant flash. + * the number of words following the packet header is 0, no MAC + * is present and the packet is not authenticated. If 1, the + * packet is a crypto-NAK; if 3, the packet is authenticated + * with DES; if 5, the packet is authenticated with MD5. If 2 or + * 4, the packet is a runt and discarded forthwith. If greater + * than 5, an extension field is present, so we subtract the + * length of the field and go around again. */ authlen = LEN_PKT_NOMAC; has_mac = rbufp->recv_length - authlen; @@ -491,21 +502,58 @@ receive( * address used to construct the autokey is the unicast address * of the interface. However, if the sender is a broadcaster, * the interface broadcast address is used instead. - * Notwithstanding this technobabble, if the sender is a + & Notwithstanding this technobabble, if the sender is a * multicaster, the broadcast address is null, so we use the * unicast address anyway. Don't ask. */ - peer = findpeer(&rbufp->recv_srcadr, rbufp->dstadr, rbufp->fd, - hismode, &retcode); - is_authentic = 0; + peer = findpeer(&rbufp->recv_srcadr, rbufp->dstadr, hismode, + &retcode); dstadr_sin = &rbufp->dstadr->sin; + NTOHL_FP(&pkt->org, &p_org); + NTOHL_FP(&pkt->rec, &p_rec); + NTOHL_FP(&pkt->xmt, &p_xmt); + + /* + * Authentication is conditioned by three switches: + * + * NOPEER (RES_NOPEER) do not mobilize an association unless + * authenticated + * NOTRUST (RES_DONTTRUST) do not allow access unless + * authenticated (implies NOPEER) + * enable (sys_authenticate) master NOPEER switch, by default + * on + * + * The NOPEER and NOTRUST can be specified on a per-client basis + * using the restrict command. The enable switch if on implies + * NOPEER for all clients. There are four outcomes: + * + * NONE The packet has no MAC. + * OK the packet has a MAC and authentication succeeds + * ERROR the packet has a MAC and authentication fails + * CRYPTO crypto-NAK. The MAC has four octets only. + * + * Note: The AUTH(x, y) macro is used to filter outcomes. If x + * is zero, acceptable outcomes of y are NONE and OK. If x is + * one, the only acceptable outcome of y is OK. + */ if (has_mac == 0) { + is_authentic = AUTH_NONE; /* not required */ #ifdef DEBUG if (debug) - printf("receive: at %ld %s<-%s mode %d code %d\n", - current_time, stoa(&rbufp->dstadr->sin), - stoa(&rbufp->recv_srcadr), hismode, - retcode); + printf("receive: at %ld %s<-%s mode %d code %d auth %d\n", + current_time, stoa(dstadr_sin), + stoa(&rbufp->recv_srcadr), hismode, retcode, + is_authentic); +#endif + } else if (has_mac == 4) { + is_authentic = AUTH_CRYPTO; /* crypto-NAK */ +#ifdef DEBUG + if (debug) + printf( + "receive: at %ld %s<-%s mode %d code %d keyid %08x len %d mac %d auth %d\n", + current_time, stoa(dstadr_sin), + stoa(&rbufp->recv_srcadr), hismode, retcode, + skeyid, authlen, has_mac, is_authentic); #endif } else { #ifdef OPENSSL @@ -548,8 +596,14 @@ receive( * broadcast address when available; * otherwise, use the unicast address * found when the association was - * mobilized. + * mobilized. However, if this is from + * the wildcard interface, game over. */ + if (crypto_flags && rbufp->dstadr == + any_interface) { + sys_restricted++; + return; /* no wildcard */ + } pkeyid = 0; if (!SOCKNUL(&rbufp->dstadr->bcast)) dstadr_sin = @@ -588,15 +642,15 @@ receive( * Compute the cryptosum. Note a clogging attack may * succeed in bloating the key cache. If an autokey, * purge it immediately, since we won't be needing it - * again. If the packet is authentic, it may mobilize an - * association. + * again. If the packet is authentic, it can mobilize an + * association. Note that there is no key zero. */ - if (authdecrypt(skeyid, (u_int32 *)pkt, authlen, + if (!authdecrypt(skeyid, (u_int32 *)pkt, authlen, has_mac)) { - is_authentic = 1; - restrict_mask &= ~RES_DONTTRUST; - } else { + is_authentic = AUTH_ERROR; sys_badauth++; + } else { + is_authentic = AUTH_OK; } #ifdef OPENSSL if (skeyid > NTP_MAXKEY) @@ -608,97 +662,114 @@ receive( "receive: at %ld %s<-%s mode %d code %d keyid %08x len %d mac %d auth %d\n", current_time, stoa(dstadr_sin), stoa(&rbufp->recv_srcadr), hismode, retcode, - skeyid, authlen, has_mac, - is_authentic); + skeyid, authlen, has_mac, is_authentic); #endif } /* * The association matching rules are implemented by a set of - * routines and a table in ntp_peer.c. A packet matching an - * association is processed by that association. If not and - * certain conditions prevail, then an ephemeral association is - * mobilized: a broadcast packet mobilizes a broadcast client + * routines and an association table. A packet matching an + * association is processed by the peer process for that + * association. If there are no errors, an ephemeral association + * is mobilized: a broadcast packet mobilizes a broadcast client * aassociation; a manycast server packet mobilizes a manycast * client association; a symmetric active packet mobilizes a - * symmetric passive association. And, the adventure - * continues... + * symmetric passive association. */ switch (retcode) { + + /* + * This is a client mode packet not matching any association. If + * an ordinary client, simply toss a server mode packet back + * over the fence. If a manycast client, we have to work a + * little harder. + */ case AM_FXMIT: /* - * This is a client mode packet not matching a known - * association. If from a manycast client we run a few - * sanity checks before deciding to send a unicast - * server response. Otherwise, it must be a client - * request, so send a server response and go home. + * The vanilla case is when this is not a multicast + * interface. If authentication succeeds, return a + * server mode packet; if not and the key ID is nonzero, + * return a crypto-NAK. */ - if (sys_manycastserver && (rbufp->dstadr->flags & - INT_MULTICAST)) { - - /* - * There is no reason to respond to a request if - * our time is worse than the manycaster or it - * has already synchronized to us. - */ - if (sys_peer == NULL || - PKT_TO_STRATUM(pkt->stratum) < - sys_stratum || (sys_cohort && - PKT_TO_STRATUM(pkt->stratum) == - sys_stratum) || - rbufp->dstadr->addr_refid == pkt->refid) - return; /* manycast dropped */ + if (!(rbufp->dstadr->flags & INT_MCASTOPEN)) { + if (AUTH(restrict_mask & RES_DONTTRUST, + is_authentic)) + fast_xmit(rbufp, MODE_SERVER, skeyid, + restrict_mask); + else if (is_authentic == AUTH_ERROR) + fast_xmit(rbufp, MODE_SERVER, 0, + restrict_mask); + return; /* hooray */ } /* - * Note that we don't require an authentication check - * here, since we can't set the system clock; but, we do - * send a crypto-NAK to tell the caller about this. + * This must be manycast. Do not respond if not + * configured as a manycast server. */ - if (has_mac && !is_authentic) - fast_xmit(rbufp, MODE_SERVER, 0, restrict_mask); - else - fast_xmit(rbufp, MODE_SERVER, skeyid, - restrict_mask); - return; + if (!sys_manycastserver) { + sys_restricted++; + return; /* not enabled */ + } - case AM_MANYCAST: + /* + * Do not respond if unsynchronized or stratum is below + * the floor or at or above the ceiling. + */ + if (sys_leap == LEAP_NOTINSYNC || sys_stratum < + sys_floor || sys_stratum >= sys_ceiling) + return; /* bad stratum */ /* - * This is a server mode packet returned in response to - * a client mode packet sent to a multicast group - * address. The originate timestamp is a good nonce to - * reliably associate the reply with what was sent. If - * there is no match, that's curious and could be an - * intruder attempting to clog, so we just ignore it. - * - * First, make sure the packet is authentic and not - * restricted. If so and the manycast association is - * found, we mobilize a client association and copy - * pertinent variables from the manycast association to - * the new client association. - * - * There is an implosion hazard at the manycast client, - * since the manycast servers send the server packet - * immediately. If the guy is already here, don't fire - * up a duplicate. + * Do not respond if our stratum is greater than the + * manycaster or it has already synchronized to us. */ - if (restrict_mask & RES_DONTTRUST) { - sys_restricted++; - return; /* no trust */ - } + if (sys_peer == NULL || hisstratum < sys_stratum || + (sys_cohort && hisstratum == sys_stratum) || + rbufp->dstadr->addr_refid == pkt->refid) + return; /* no help */ - if (sys_authenticate && !is_authentic) - return; /* bad auth */ + /* + * Respond only if authentication succeeds. Don't do a + * crypto-NAK, as that would not be useful. + */ + if (AUTH(restrict_mask & RES_DONTTRUST, is_authentic)) + fast_xmit(rbufp, MODE_SERVER, skeyid, + restrict_mask); - if ((peer2 = findmanycastpeer(rbufp)) == NULL) - return; /* no assoc match */ + return; /* hooray */ - if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, - MODE_CLIENT, PKT_VERSION(pkt->li_vn_mode), - NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_IBURST, MDF_UCAST | - MDF_ACLNT, 0, skeyid)) == NULL) + /* + * This is a server mode packet returned in response to a client + * mode packet sent to a multicast group address. The origin + * timestamp is a good nonce to reliably associate the reply + * with what was sent. If there is no match, that's curious and + * could be an intruder attempting to clog, so we just ignore + * it. + * + * If the packet is authentic and the manycast association is + * found, we mobilize a client association and copy pertinent + * variables from the manycast association to the new client + * association. If not, just ignore the packet. + * + * There is an implosion hazard at the manycast client, since + * the manycast servers send the server packet immediately. If + * the guy is already here, don't fire up a duplicate. + */ + case AM_MANYCAST: + if (!AUTH(sys_authenticate | (restrict_mask & + (RES_NOPEER | RES_DONTTRUST)), is_authentic)) + return; /* bad auth */ + + if ((peer2 = findmanycastpeer(rbufp)) == NULL) { + sys_restricted++; + return; /* not enabled */ + } + if ((peer = newpeer(&rbufp->recv_srcadr, + rbufp->dstadr, MODE_CLIENT, + hisversion, NTP_MINDPOLL, NTP_MAXDPOLL, + FLAG_IBURST | FLAG_PREEMPT, MDF_UCAST | MDF_ACLNT, + 0, skeyid)) == NULL) return; /* system error */ /* @@ -707,260 +778,223 @@ receive( peer->ttl = peer2->ttl; break; - case AM_NEWPASS: + /* + * This is the first packet received from a broadcast server. If + * the packet is authentic and we are enabled as broadcast + * client, mobilize a broadcast client association. We don't + * kiss any frogs here. + */ + case AM_NEWBCL: + if (!AUTH(sys_authenticate | (restrict_mask & + (RES_NOPEER | RES_DONTTRUST)), is_authentic)) + return; /* bad auth */ /* - * This is the first packet received from a symmetric - * active peer. First, make sure it is authentic and not - * restricted. If so, mobilize a passive association. - * If authentication fails send a crypto-NAK; otherwise, - * kiss the frog. + * Do not respond if unsynchronized or stratum is below + * the floor or at or above the ceiling. */ - if (restrict_mask & RES_DONTTRUST) { - sys_restricted++; - return; /* no trust */ - } - if (sys_authenticate && !is_authentic) { - fast_xmit(rbufp, MODE_PASSIVE, 0, - restrict_mask); - return; /* bad auth */ - } - if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, - MODE_PASSIVE, PKT_VERSION(pkt->li_vn_mode), - NTP_MINDPOLL, NTP_MAXDPOLL, 0, MDF_UCAST, 0, - skeyid)) == NULL) - return; /* system error */ - - break; + if (hisleap == LEAP_NOTINSYNC || hisstratum < + sys_floor || hisstratum >= sys_ceiling) + return; /* bad stratum */ - case AM_NEWBCL: + switch (sys_bclient) { /* - * This is the first packet received from a broadcast - * server. First, make sure it is authentic and not - * restricted and that we are a broadcast client. If so, - * mobilize a broadcast client association. We don't - * kiss any frogs here. + * If not enabled, just skedaddle. */ - if (restrict_mask & RES_DONTTRUST) { + case 0: sys_restricted++; - return; /* no trust */ - } - if (sys_authenticate && !is_authentic) - return; /* bad auth */ - - if (!sys_bclient) - return; /* not a client */ + return; /* not enabled */ - if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, - MODE_CLIENT, PKT_VERSION(pkt->li_vn_mode), - NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_MCAST | - FLAG_IBURST, MDF_BCLNT, 0, skeyid)) == NULL) - return; /* system error */ -#ifdef OPENSSL /* - * Danger looms. If this is autokey, go process the - * extension fields. If something goes wrong, abandon - * ship and don't trust subsequent packets. + * Execute the initial volley in order to calibrate the + * propagation delay and run the Autokey protocol, if + * enabled. */ - if (crypto_flags) { - if ((rval = crypto_recv(peer, rbufp)) != - XEVNT_OK) { - struct sockaddr_storage mskadr_sin; - - unpeer(peer); - sys_restricted++; - SET_HOSTMASK(&mskadr_sin, - rbufp->recv_srcadr.ss_family); - hack_restrict(RESTRICT_FLAGS, - &rbufp->recv_srcadr, &mskadr_sin, - 0, RES_DONTTRUST | RES_TIMEOUT); -#ifdef DEBUG - if (debug) - printf( - "packet: bad exten %x\n", - rval); -#endif - } - } + case 1: + if ((peer = newpeer(&rbufp->recv_srcadr, + rbufp->dstadr, MODE_CLIENT, hisversion, + NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_MCAST | + FLAG_IBURST, MDF_BCLNT, 0, skeyid)) == + NULL) + return; /* system error */ +#ifdef OPENSSL + if (skeyid > NTP_MAXKEY) + crypto_recv(peer, rbufp); #endif /* OPENSSL */ - return; - - case AM_POSSBCL: + return; /* hooray */ - /* - * This is a broadcast packet received in client mode. - * It could happen if the initial client/server volley - * is not complete before the next broadcast packet is - * received. Be liberal in what we accept. - */ - case AM_PROCPKT: /* - * This is a symmetric mode packet received in symmetric - * mode, a server packet received in client mode or a - * broadcast packet received in broadcast client mode. - * If it is restricted, this is very strange because it - * is rude to send a packet to a restricted address. If - * anyway, flash a restrain kiss and skedaddle to - * Seattle. If not authentic, leave a light on and - * continue. + * Do not execute the initial volley. */ - peer->flash = 0; - if (restrict_mask & RES_DONTTRUST) { - sys_restricted++; - if (peer->flags & FLAG_CONFIG) - peer_clear(peer, "RSTR"); - else - unpeer(peer); - return; /* no trust */ + case 2: +#ifdef OPENSSL + /* + * If a two-way exchange is not possible, + * neither is Autokey. + */ + if (skeyid > NTP_MAXKEY) { + msyslog(LOG_INFO, + "receive: autokey requires two-way communication"); + return; /* no autokey */ + } +#endif /* OPENSSL */ + if ((peer = newpeer(&rbufp->recv_srcadr, + rbufp->dstadr, MODE_BCLIENT, hisversion, + NTP_MINDPOLL, NTP_MAXDPOLL, 0, MDF_BCLNT, 0, + skeyid)) == NULL) + return; /* system error */ } - if (has_mac && !is_authentic) - peer->flash |= TEST5; /* bad auth */ break; - default: + /* + * This is the first packet received from a symmetric active + * peer. If the packet is authentic and the first he sent, + * mobilize a passive association. If not, kiss the frog. + */ + case AM_NEWPASS: /* - * Invalid mode combination. This happens when a passive - * mode packet arrives and matches another passive - * association or no association at all, or when a - * server mode packet arrives and matches a broadcast - * client association. This is usually the result of - * reconfiguring a client on-fly. If authenticated - * passive mode packet, send a crypto-NAK; otherwise, - * ignore it. + * If the inbound packet is correctly authenticated and + * enabled, a symmetric passive association is + * mobilized. If not but correctly authenticated, a + * symmetric active response is sent. If authentication + * fails, send a crypto-NAK packet. */ - if (has_mac && hismode == MODE_PASSIVE) - fast_xmit(rbufp, MODE_ACTIVE, 0, restrict_mask); -#ifdef DEBUG - if (debug) - printf("receive: bad protocol %d\n", retcode); -#endif - return; - } + if (!AUTH(restrict_mask & RES_DONTTRUST, is_authentic)) + { + if (is_authentic == AUTH_ERROR) + fast_xmit(rbufp, MODE_ACTIVE, 0, + restrict_mask); + return; /* bad auth */ + } + if (!AUTH(sys_authenticate | (restrict_mask & + RES_NOPEER), is_authentic)) { + fast_xmit(rbufp, MODE_ACTIVE, skeyid, + restrict_mask); + return; /* hooray */ + } + + /* + * Do not respond if stratum is below the floor. + */ + if (hisstratum < sys_floor) + return; /* bad stratum */ + + if ((peer = newpeer(&rbufp->recv_srcadr, + rbufp->dstadr, MODE_PASSIVE, hisversion, + NTP_MINDPOLL, NTP_MAXDPOLL, 0, MDF_UCAST, 0, + skeyid)) == NULL) + return; /* system error */ + break; /* - * We do a little homework. Note we can get here with an - * authentication error. We Need to do this in order to validate - * a crypto-NAK later. Note the order of processing; it is very - * important to avoid livelocks, deadlocks and lockpicks. + * Process regular packet. Nothing special. */ - peer->timereceived = current_time; - peer->received++; - if (peer->flash & TEST5) - peer->flags &= ~FLAG_AUTHENTIC; - else - peer->flags |= FLAG_AUTHENTIC; - NTOHL_FP(&pkt->org, &p_org); - NTOHL_FP(&pkt->xmt, &p_xmt); + case AM_PROCPKT: + break; /* - * If the packet is an old duplicate, we let it through so the - * extension fields will be processed. + * A passive packet matches a passive association. This is + * usually the result of reconfiguring a client on the fly. As + * this association might be legitamate and this packet an + * attempt to deny service, just ignore it. */ - if (L_ISEQU(&peer->org, &p_xmt)) { /* test 1 */ - peer->flash |= TEST1; /* dupe */ - /* fall through */ + case AM_ERR: + return; /* - * For broadcast server mode, loopback checking is disabled. An - * authentication error probably means the server restarted or - * rolled a new private value. If so, dump the association - * and wait for the next message. + * For everything else there is the bit bucket. */ - } else if (hismode == MODE_BROADCAST) { - if (peer->flash & TEST5) { - unpeer(peer); - return; - } - /* fall through */ - - /* - * For server and symmetric modes, if the association transmit - * timestamp matches the packet originate timestamp, loopback is - * confirmed. Note in symmetric modes this also happens when the - * first packet from the active peer arrives at the newly - * mobilized passive peer. An authentication error probably - * means the server or peer restarted or rolled a new private - * value, but could be an intruder trying to stir up trouble. - * However, if this is a crypto-NAK, we know it is authentic, so - * dump the association and wait for the next message. - */ - } else if (L_ISEQU(&peer->xmt, &p_org)) { - if (peer->flash & TEST5) { - if (has_mac == 4 && pkt->exten[0] == 0) { - if (peer->flags & FLAG_CONFIG) - peer_clear(peer, "AUTH"); - else - unpeer(peer); - } - return; - } - /* fall through */ + default: + return; + } + peer->flash &= ~PKT_TEST_MASK; /* - * If the client or passive peer has never transmitted anything, - * this is either the first message from a symmetric peer or - * possibly a duplicate received before the transmit timeout. - * Pass it on. + * Next comes a rigorous schedule of timestamp checking. If the + * transmit timestamp is zero, the server is horribly broken. */ - } else if (L_ISZERO(&peer->xmt)) { - /* fall through */ + if (L_ISZERO(&p_xmt)) { + return; /* read rfc1305 */ /* - * Now it gets interesting. We have transmitted at least one - * packet. If the packet originate timestamp is nonzero, it - * does not match the association transmit timestamp, which is a - * loopback error. This error might mean a manycast server has - * answered a manycast honk from us and we already have an - * association for him, in which case quietly drop the packet - * here. It might mean an old duplicate, dropped packet or - * intruder replay, in which case we drop it later after - * extension field processing, but never let it touch the time - * values. + * If the transmit timestamp duplicates a previous one, the + * packet is a replay. This prevents the bad guys from replaying + * the most recent packet, authenticated or not. */ - } else if (!L_ISZERO(&p_org)) { - if (peer->cast_flags & MDF_ACLNT) - return; /* not a client */ + } else if (L_ISEQU(&peer->org, &p_xmt)) { + peer->flash |= TEST1; + peer->oldpkt++; + return; /* duplicate packet */ + - peer->flash |= TEST2; - /* fall through */ + /* + * If this is a broadcast mode packet, skip further checking. + */ + } else if (hismode != MODE_BROADCAST) { + if (L_ISZERO(&p_org)) + peer->flash |= TEST3; /* protocol unsynch */ + else if (!L_ISEQU(&p_org, &peer->xmt)) + peer->flash |= TEST2; /* bogus packet */ + } /* - * The packet originate timestamp is zero, meaning the other guy - * either didn't receive the first packet or died and restarted. - * If the association originate timestamp is zero, this is the - * first packet received, so we pass it on. + * Update the origin and destination timestamps. If + * unsynchronized or bogus abandon ship. If the crypto machine + * breaks, light the crypto bit and plaint the log. */ - } else if (L_ISZERO(&peer->org)) { - /* fall through */ + peer->org = p_xmt; + peer->rec = rbufp->recv_time; + if (peer->flash & PKT_TEST_MASK) { +#ifdef OPENSSL + if (crypto_flags && (peer->flags & FLAG_SKEY)) { + rval = crypto_recv(peer, rbufp); + if (rval != XEVNT_OK) { + peer_clear(peer, "CRYP"); + peer->flash |= TEST9; /* crypto error */ + } + } +#endif /* OPENSSL */ + return; /* unsynch */ + } /* - * The other guy has restarted and we are still on the wire. We - * should demobilize/clear and get out of Dodge. If this is - * symmetric mode, we should also send a crypto-NAK. + * The timestamps are valid and the receive packet matches the + * last one sent. If the packet is a crypto-NAK, the server + * might have just changed keys. We reset the association + * and restart the protocol. */ - } else { - if (hismode == MODE_ACTIVE) - fast_xmit(rbufp, MODE_PASSIVE, 0, - restrict_mask); - else if (hismode == MODE_PASSIVE) + if (is_authentic == AUTH_CRYPTO) { + peer_clear(peer, "AUTH"); + return; /* crypto-NAK */ + + /* + * If the association is authenticated, the key ID is nonzero + * and received packets must be authenticated. This is designed + * to avoid a bait-and-switch attack, which was possible in past + * versions. If symmetric modes, return a crypto-NAK. The peer + * should restart the protocol. + */ + } else if (!AUTH(peer->keyid || (restrict_mask & RES_DONTTRUST), + is_authentic)) { + peer->flash |= TEST5; + if (hismode == MODE_ACTIVE || hismode == MODE_PASSIVE) fast_xmit(rbufp, MODE_ACTIVE, 0, restrict_mask); -#if DEBUG - if (debug) - printf("receive: dropped %03x\n", peer->flash); -#endif - if (peer->flags & FLAG_CONFIG) - peer_clear(peer, "DROP"); - else - unpeer(peer); - return; - } - if (peer->flash & ~TEST2) { - return; + return; /* bad auth */ } + /* + * That was hard and I am sweaty, but the packet is squeaky + * clean. Get on with real work. + */ + peer->received++; + peer->timereceived = current_time; + if (is_authentic == AUTH_OK) + peer->flags |= FLAG_AUTHENTIC; + else + peer->flags &= ~FLAG_AUTHENTIC; #ifdef OPENSSL /* * More autokey dance. The rules of the cha-cha are as follows: @@ -981,17 +1015,27 @@ receive( * matches the previous key ID or ultimate original key ID * obtained from the broadcaster or symmetric peer. If no * match, sit the dance and wait for timeout. + * + * In case of crypto error, fire the orchestra and stop dancing. + * This is considered a permanant error, so light the crypto bit + * to suppress further requests. If preemptable or ephemeral, + * scuttle the ship. */ if (crypto_flags && (peer->flags & FLAG_SKEY)) { - peer->flash |= TEST10; + peer->flash |= TEST8; rval = crypto_recv(peer, rbufp); if (rval != XEVNT_OK) { - /* fall through */ + peer_clear(peer, "CRYP"); + peer->flash |= TEST9; /* crypto error */ + if (peer->flags & FLAG_PREEMPT || + !(peer->flags & FLAG_CONFIG)) + unpeer(peer); + return; } else if (hismode == MODE_SERVER) { if (skeyid == peer->keyid) - peer->flash &= ~TEST10; - } else if (!peer->flash & TEST10) { + peer->flash &= ~TEST8; + } else if (!(peer->flash & TEST8)) { peer->pkeyid = skeyid; } else if ((ap = (struct autokey *)peer->recval.ptr) != NULL) { @@ -1000,7 +1044,7 @@ receive( for (i = 0; ; i++) { if (tkeyid == peer->pkeyid || tkeyid == ap->key) { - peer->flash &= ~TEST10; + peer->flash &= ~TEST8; peer->pkeyid = skeyid; break; } @@ -1011,8 +1055,8 @@ receive( tkeyid, pkeyid, 0); } } - if (!(peer->crypto & CRYPTO_FLAG_PROV)) /* test 11 */ - peer->flash |= TEST11; /* not proventic */ + if (!(peer->crypto & CRYPTO_FLAG_PROV)) /* test 9 */ + peer->flash |= TEST8; /* not proventic */ /* * If the transmit queue is nonempty, clamp the host @@ -1020,65 +1064,28 @@ receive( */ if (peer->cmmd != 0) { peer->ppoll = pkt->ppoll; - poll_update(peer, 0); - } - - /* - * If the return code from extension field processing is - * not okay, we scrub the association and start over. - */ - if (rval != XEVNT_OK) { - - /* - * If the return code is bad, the crypto machine - * may be jammed or an intruder may lurk. First, - * we demobilize the association, then see if - * the error is recoverable. - */ - if (peer->flags & FLAG_CONFIG) - peer_clear(peer, "CRYP"); - else - unpeer(peer); -#ifdef DEBUG - if (debug) - printf("packet: bad exten %x\n", rval); -#endif - return; - } - - /* - * If TEST10 is lit, the autokey sequence has broken, - * which probably means the server has refreshed its - * private value. We reset the poll interval to the - & minimum and scrub the association clean. - */ - if (peer->flash & TEST10 && peer->crypto & - CRYPTO_FLAG_AUTO) { - poll_update(peer, peer->minpoll); -#ifdef DEBUG - if (debug) - printf( - "packet: bad auto %03x\n", - peer->flash); -#endif - if (peer->flags & FLAG_CONFIG) - peer_clear(peer, "AUTO"); - else - unpeer(peer); - return; + poll_update(peer, peer->hpoll); } } #endif /* OPENSSL */ /* - * We have survived the gaunt. Forward to the packet routine. If - * a symmetric passive association has been mobilized and the - * association doesn't deserve to live, it will die in the - * transmit routine if not reachable after timeout. However, if - * either symmetric mode and the crypto code has something - * urgent to say, we expedite the response. + * The dance is complete and the flash bits have been lit. Toss + * the packet over the fence for processing, which may light up + * more flashers. */ - process_packet(peer, pkt, &rbufp->recv_time); + process_packet(peer, pkt); + + /* + * Well, that was nice. If TEST4 is lit, either the crypto + * machine jammed or a kiss-o'-death packet flew in, either of + * which is fatal. + */ + if (peer->flash & TEST4) { + msyslog(LOG_INFO, "receive: fatal error %04x for %s", + peer->flash, stoa(&peer->srcadr)); + return; + } } @@ -1091,23 +1098,15 @@ receive( void process_packet( register struct peer *peer, - register struct pkt *pkt, - l_fp *recv_ts + register struct pkt *pkt ) { - l_fp t34, t21; + double t34, t21; double p_offset, p_del, p_disp; - double dtemp; l_fp p_rec, p_xmt, p_org, p_reftime; l_fp ci; u_char pmode, pleap, pstratum; - /* - * Swap header fields and keep the books. The books amount to - * the receive timestamp and poll interval in the header. We - * need these even if there are other problems in order to crank - * up the state machine. - */ sys_processed++; peer->processed++; p_del = FPTOD(NTOHS_FP(pkt->rootdelay)); @@ -1124,106 +1123,97 @@ process_packet( pstratum = PKT_TO_STRATUM(pkt->stratum); /* - * Test for unsynchronized server. + * Test for kiss-o'death packet) */ - if (L_ISHIS(&peer->org, &p_xmt)) /* count old packets */ - peer->oldpkt++; - if (pmode != MODE_BROADCAST && (L_ISZERO(&p_rec) || - L_ISZERO(&p_org))) /* test 3 */ - peer->flash |= TEST3; /* unsynch */ - if (L_ISZERO(&p_xmt)) /* test 3 */ - peer->flash |= TEST3; /* unsynch */ + if (pleap == LEAP_NOTINSYNC && pstratum == STRATUM_UNSPEC) { + if (memcmp(&pkt->refid, "DENY", 4) == 0) { + peer_clear(peer, "DENY"); + peer->flash |= TEST4; /* access denied */ + } + } /* - * If any tests fail, the packet is discarded leaving only the - * timestamps, which are enough to get the protocol started. The - * originate timestamp is copied from the packet transmit - * timestamp and the receive timestamp is copied from the - * packet receive timestamp. If okay so far, we save the leap, - * stratum and refid for billboards. + * Capture the header values. */ - peer->org = p_xmt; - peer->rec = *recv_ts; - if (peer->flash) { -#ifdef DEBUG - if (debug) - printf("packet: bad data %03x from address: %s\n", - peer->flash, stoa(&peer->srcadr)); -#endif - return; - } + record_raw_stats(&peer->srcadr, peer->dstadr ? &peer->dstadr->sin : NULL, &p_org, + &p_rec, &p_xmt, &peer->rec); peer->leap = pleap; - peer->stratum = pstratum; - peer->refid = pkt->refid; + peer->stratum = min(pstratum, STRATUM_UNSPEC); + peer->pmode = pmode; + peer->ppoll = pkt->ppoll; + peer->precision = pkt->precision; + peer->rootdelay = p_del; + peer->rootdispersion = p_disp; + peer->refid = pkt->refid; /* network byte order */ + peer->reftime = p_reftime; /* - * Test for valid peer data (tests 6-8) + * Verify the server is synchronized; that is, the leap bits and + * stratum are valid, the root delay and root dispersion are + * valid and the reference timestamp is not later than the + * transmit timestamp. */ - ci = p_xmt; - L_SUB(&ci, &p_reftime); - LFPTOD(&ci, dtemp); if (pleap == LEAP_NOTINSYNC || /* test 6 */ - pstratum >= STRATUM_UNSPEC || dtemp < 0) - peer->flash |= TEST6; /* bad synch */ - if (!(peer->flags & FLAG_CONFIG) && sys_peer != NULL) { /* test 7 */ - if (pstratum > sys_stratum && pmode != MODE_ACTIVE) - peer->flash |= TEST7; /* bad stratum */ - } - if (p_del < 0 || p_disp < 0 || p_del / /* test 8 */ - 2 + p_disp >= MAXDISPERSE) - peer->flash |= TEST8; /* bad peer values */ + pstratum < sys_floor || pstratum >= sys_ceiling) + peer->flash |= TEST6; /* peer not synch */ + if (p_del < 0 || p_disp < 0 || p_del / /* test 7 */ + 2 + p_disp >= MAXDISPERSE || !L_ISHIS(&p_xmt, &p_reftime)) + peer->flash |= TEST7; /* bad header */ /* * If any tests fail at this point, the packet is discarded. + * Note that some flashers may have already been set in the + * receive() routine. */ - if (peer->flash) { + if (peer->flash & PKT_TEST_MASK) { #ifdef DEBUG if (debug) - printf("packet: bad header %03x\n", + printf("packet: flash header %04x\n", peer->flash); #endif return; } - - /* - * The header is valid. Capture the remaining header values and - * mark as reachable. - */ - record_raw_stats(&peer->srcadr, &peer->dstadr->sin, &p_org, - &p_rec, &p_xmt, &peer->rec); - peer->pmode = pmode; - peer->ppoll = pkt->ppoll; - peer->precision = pkt->precision; - peer->rootdelay = p_del; - peer->rootdispersion = p_disp; - peer->reftime = p_reftime; if (!(peer->reach)) { report_event(EVNT_REACH, peer); peer->timereachable = current_time; } + poll_update(peer, peer->hpoll); peer->reach |= 1; - peer->unreach = 0; - poll_update(peer, 0); /* - * If running in a client/server association, calculate the - * clock offset c, roundtrip delay d and dispersion e. We use - * the equations (reordered from those in the spec). Note that, - * in a broadcast association, org has been set to the time of - * last reception. Note the computation of dispersion includes - * the system precision plus that due to the frequency error - * since the originate time. + * For a client/server association, calculate the clock offset, + * roundtrip delay and dispersion. The equations are reordered + * from the spec for more efficient use of temporaries. For a + * broadcast association, offset the last measurement by the + * computed delay during the client/server volley. Note that + * org has been set to the time of last reception. Note the + * computation of dispersion includes the system precision plus + * that due to the frequency error since the origin time. + * + * It is very important to respect the hazards of overflow. The + * only permitted operation on raw timestamps is subtraction, + * where the result is a signed quantity spanning from 68 years + * in the past to 68 years in the future. To avoid loss of + * precision, these calculations are done using 64-bit integer + * arithmetic. However, the offset and delay calculations are + * sums and differences of these first-order differences, which + * if done using 64-bit integer arithmetic, would be valid over + * only half that span. Since the typical first-order + * differences are usually very small, they are converted to 64- + * bit doubles and all remaining calculations done in floating- + * point arithmetic. This preserves the accuracy while retaining + * the 68-year span. * * Let t1 = p_org, t2 = p_rec, t3 = p_xmt, t4 = peer->rec: */ - t34 = p_xmt; /* t3 - t4 */ - L_SUB(&t34, &peer->rec); - t21 = p_rec; /* t2 - t1 */ - L_SUB(&t21, &p_org); + ci = p_xmt; /* t3 - t4 */ + L_SUB(&ci, &peer->rec); + LFPTOD(&ci, t34); + ci = p_rec; /* t2 - t1 */ + L_SUB(&ci, &p_org); + LFPTOD(&ci, t21); ci = peer->rec; /* t4 - t1 */ L_SUB(&ci, &p_org); - LFPTOD(&ci, p_disp); - p_disp = clock_phi * max(p_disp, LOGTOD(sys_precision)); /* * If running in a broadcast association, the clock offset is @@ -1234,48 +1224,29 @@ process_packet( * MODE_BCLIENT mode. The next broadcast message after that * computes the broadcast offset and clears FLAG_MCAST. */ - ci = t34; if (pmode == MODE_BROADCAST) { + p_offset = t34; if (peer->flags & FLAG_MCAST) { - LFPTOD(&ci, p_offset); peer->estbdelay = peer->offset - p_offset; if (peer->hmode == MODE_CLIENT) return; - peer->flags &= ~FLAG_MCAST; + peer->flags &= ~(FLAG_MCAST | FLAG_BURST); } - DTOLFP(peer->estbdelay, &t34); - L_ADD(&ci, &t34); + p_offset += peer->estbdelay; p_del = peer->delay; + p_disp = 0; } else { - L_ADD(&ci, &t21); /* (t2 - t1) + (t3 - t4) */ - L_RSHIFT(&ci); - L_SUB(&t21, &t34); /* (t2 - t1) - (t3 - t4) */ - LFPTOD(&t21, p_del); + p_offset = (t21 + t34) / 2.; + p_del = t21 - t34; + LFPTOD(&ci, p_disp); + p_disp = LOGTOD(sys_precision) + + LOGTOD(peer->precision) + clock_phi * p_disp; } p_del = max(p_del, LOGTOD(sys_precision)); - LFPTOD(&ci, p_offset); - if ((peer->rootdelay + p_del) / 2. + peer->rootdispersion + - p_disp >= MAXDISPERSE) /* test 9 */ - peer->flash |= TEST9; /* bad root distance */ - - /* - * If any flasher bits remain set at this point, abandon ship. - * Otherwise, forward to the clock filter. - */ - if (peer->flash) { -#ifdef DEBUG - if (debug) - printf("packet: bad packet data %03x\n", - peer->flash); -#endif - return; - } clock_filter(peer, p_offset, p_del, p_disp); - clock_select(); record_peer_stats(&peer->srcadr, ctlpeerstatus(peer), - peer->offset, peer->delay, peer->disp, - SQRT(peer->jitter)); + peer->offset, peer->delay, peer->disp, peer->jitter); } @@ -1285,18 +1256,23 @@ process_packet( static void clock_update(void) { - u_char oleap; - u_char ostratum; + u_char oleap; + u_char ostratum; + double dtemp; /* - * Reset/adjust the system clock. Do this only if there is a - * system peer and the peer epoch is not older than the last - * update. + * There must be a system peer at this point. If we just changed + * the system peer, but have a newer sample from the old one, + * wait until newer data are available. */ - if (sys_peer == NULL) - return; - if (sys_peer->epoch <= last_time) + if (sys_poll < sys_peer->minpoll) + sys_poll = sys_peer->minpoll; + if (sys_poll > sys_peer->maxpoll) + sys_poll = sys_peer->maxpoll; + poll_update(sys_peer, sys_poll); + if (sys_peer->epoch <= sys_clocktime) return; + #ifdef DEBUG if (debug) printf("clock_update: at %ld assoc %d \n", current_time, @@ -1304,53 +1280,85 @@ clock_update(void) #endif oleap = sys_leap; ostratum = sys_stratum; - switch (local_clock(sys_peer, sys_offset, sys_syserr)) { + switch (local_clock(sys_peer, sys_offset)) { /* - * Clock is too screwed up. Just exit for now. + * Clock exceeds panic threshold. Life as we know it ends. */ case -1: report_event(EVNT_SYSFAULT, NULL); exit (-1); - /*NOTREACHED*/ + /* not reached */ /* * Clock was stepped. Flush all time values of all peers. */ - case 1: + case 2: clear_all(); - sys_peer = NULL; + sys_leap = LEAP_NOTINSYNC; sys_stratum = STRATUM_UNSPEC; - memcpy(&sys_refid, "STEP", 4); - sys_poll = NTP_MINPOLL; + sys_peer = NULL; + sys_rootdelay = 0; + sys_rootdispersion = 0; + memcpy(&sys_refid, "STEP", 4); report_event(EVNT_CLOCKRESET, NULL); -#ifdef OPENSSL - if (oleap != LEAP_NOTINSYNC) - expire_all(); -#endif /* OPENSSL */ break; /* - * Update the system stratum, leap bits, root delay, root - * dispersion, reference ID and reference time. We also update - * select dispersion and max frequency error. If the leap - * changes, we gotta reroll the keys. + * Clock was slewed. Update the system stratum, leap bits, root + * delay, root dispersion, reference ID and reference time. If + * the leap changes, we gotta reroll the keys. Except for + * reference clocks, the minimum dispersion increment is not + * less than sys_mindisp. */ - default: - sys_stratum = (u_char) (sys_peer->stratum + 1); - if (sys_stratum == 1 || sys_stratum == STRATUM_UNSPEC) - sys_refid = sys_peer->refid; - else - sys_refid = sys_peer_refid; + case 1: + sys_leap = leap_next; + sys_stratum = min(sys_peer->stratum + 1, + STRATUM_UNSPEC); sys_reftime = sys_peer->rec; - sys_rootdelay = sys_peer->rootdelay + sys_peer->delay; - sys_leap = leap_consensus; + + /* + * In orphan mode the stratum defaults to the orphan + * stratum. The root delay is set to a random value + * generated at startup. The root dispersion is set from + * the peer dispersion; the peer root dispersion is + * ignored. + */ + dtemp = sys_peer->disp + clock_phi * (current_time - + sys_peer->update) + sys_jitter + + fabs(sys_peer->offset); +#ifdef REFCLOCK + if (!(sys_peer->flags & FLAG_REFCLOCK) && dtemp < + sys_mindisp) + dtemp = sys_mindisp; +#else + if (dtemp < sys_mindisp) + dtemp = sys_mindisp; +#endif /* REFCLOCK */ + if (sys_stratum >= sys_orphan) { + sys_stratum = sys_orphan; + sys_rootdelay = sys_peer->delay; + sys_rootdispersion = dtemp; + } else { + sys_rootdelay = sys_peer->delay + + sys_peer->rootdelay; + sys_rootdispersion = dtemp + + sys_peer->rootdispersion; + } if (oleap == LEAP_NOTINSYNC) { report_event(EVNT_SYNCCHG, NULL); #ifdef OPENSSL expire_all(); + crypto_update(); #endif /* OPENSSL */ } + break; + /* + * Popcorn spike or step threshold exceeded. Pretend it never + * happened. + */ + default: + break; } if (ostratum != sys_stratum) report_event(EVNT_PEERSTCHG, NULL); @@ -1363,110 +1371,114 @@ clock_update(void) void poll_update( struct peer *peer, - int hpoll + int mpoll ) { -#ifdef OPENSSL - int oldpoll; -#endif /* OPENSSL */ + int hpoll; + + /* + * This routine figures out when the next poll should be sent. + * That turns out to be wickedly complicated. The big problem is + * that sometimes the time for the next poll is in the past. + * Watch out for races here between the receive process and the + * poll process. The key assertion is that, if nextdate equals + * current_time, the call is from the poll process; otherwise, + * it is from the receive process. + * + * First, bracket the poll interval according to the type of + * association and options. If a fixed interval is configured, + * use minpoll. This primarily is for reference clocks, but + * works for any association. + */ + if (peer->flags & FLAG_FIXPOLL) { + hpoll = peer->minpoll; /* - * A little foxtrot to determine what controls the poll - * interval. If the peer is reachable, but the last four polls - * have not been answered, use the minimum. If declared - * truechimer, use the system poll interval. This allows each - * association to ramp up the poll interval for useless sources - * and to clamp it to the minimum when first starting up. + * The ordinary case; clamp the poll interval between minpoll + * and maxpoll. */ + } else { + hpoll = max(min(peer->maxpoll, mpoll), peer->minpoll); + } #ifdef OPENSSL - oldpoll = peer->kpoll; + /* + * Bit of crass arrogance at this point. If the poll interval + * has changed and we have a keylist, the lifetimes in the + * keylist are probably bogus. In this case purge the keylist + * and regenerate it later. + */ + if (hpoll != peer->hpoll) + key_expire(peer); #endif /* OPENSSL */ - if (hpoll > 0) { - if (hpoll > peer->maxpoll) - peer->hpoll = peer->maxpoll; - else if (hpoll < peer->minpoll) - peer->hpoll = peer->minpoll; - else - peer->hpoll = (u_char)hpoll; - } + peer->hpoll = hpoll; /* - * Bit of adventure here. If during a burst and not a poll, just - * slink away. If a poll, figure what the next poll should be. - * If a burst is pending and a reference clock or a pending - * crypto response, delay for one second. If the first sent in a - * burst, delay ten seconds for the modem to come up. For others - * in the burst, delay two seconds. - * - * In case of manycast server, make the poll interval, which is - * axtually the manycast beacon interval, eight times the system - * poll interval. Normally when the host poll interval settles - * up to 1024 s, the beacon interval settles up to 2.3 hours. + * Now we figure out if there is an override. If during the + * crypto protocol and a message is pending, make it wait not + * more than two seconds. */ #ifdef OPENSSL if (peer->cmmd != NULL && (sys_leap != LEAP_NOTINSYNC || peer->crypto)) { peer->nextdate = current_time + RESP_DELAY; + + /* + * If we get called from the receive routine while a burst is + * pending, just slink away. If from the poll routine and a + * reference clock or a pending crypto response, delay for one + * second. If this is the first sent in a burst, wait for the + * modem to come up. For others in the burst, delay two seconds. + */ } else if (peer->burst > 0) { #else /* OPENSSL */ if (peer->burst > 0) { #endif /* OPENSSL */ - if (hpoll == 0 && peer->nextdate != current_time) + if (peer->nextdate != current_time) return; #ifdef REFCLOCK else if (peer->flags & FLAG_REFCLOCK) peer->nextdate += RESP_DELAY; -#endif +#endif /* REFCLOCK */ else if (peer->flags & (FLAG_IBURST | FLAG_BURST) && peer->burst == NTP_BURST) peer->nextdate += sys_calldelay; else peer->nextdate += BURST_DELAY; - } else if (peer->cast_flags & MDF_ACAST) { - if (sys_survivors >= sys_minclock || peer->ttl >= - sys_ttlmax) - peer->kpoll = (u_char) (peer->hpoll + 3); - else - peer->kpoll = peer->hpoll; - peer->nextdate = peer->outdate + RANDPOLL(peer->kpoll); + /* + * The ordinary case; use the minimum of the host and peer + * intervals, but not less than minpoll. In other words, + * oversampling is okay but understampling is evil. + */ } else { - peer->kpoll = (u_char) max(min(peer->ppoll, - peer->hpoll), peer->minpoll); - peer->nextdate = peer->outdate + RANDPOLL(peer->kpoll); + peer->nextdate = peer->outdate + + RANDPOLL(max(min(peer->ppoll, hpoll), + peer->minpoll)); } - if (peer->nextdate < current_time) - peer->nextdate = current_time; -#ifdef OPENSSL + /* - * Bit of crass arrogance at this point. If the poll interval - * has changed and we have a keylist, the lifetimes in the - * keylist are probably bogus. In this case purge the keylist - * and regenerate it later. + * If the time for the next poll has already happened, bring it + * up to the next second after this one. This way the only way + * to get nexdate == current time is from the poll routine. */ - if (peer->kpoll != oldpoll) - key_expire(peer); -#endif /* OPENSSL */ + if (peer->nextdate <= current_time) + peer->nextdate = current_time + 1; #ifdef DEBUG if (debug > 1) printf("poll_update: at %lu %s flags %04x poll %d burst %d last %lu next %lu\n", current_time, ntoa(&peer->srcadr), peer->flags, - peer->kpoll, peer->burst, peer->outdate, + peer->hpoll, peer->burst, peer->outdate, peer->nextdate); #endif } - /* - * clear - clear peer filter registers. See Section 3.4.8 of the spec. + * peer_crypto_clear - discard crypto information */ void -peer_clear( - struct peer *peer, /* peer structure */ - char *ident /* tally lights */ - ) +peer_crypto_clear( + struct peer *peer + ) { - u_char oreach, i; - /* * If cryptographic credentials have been acquired, toss them to * Valhalla. Note that autokeys are ephemeral, in that they are @@ -1476,41 +1488,88 @@ peer_clear( * purged, too. This makes it much harder to sneak in some * unauthenticated data in the clock filter. */ - oreach = peer->reach; + DPRINTF(1, ("peer_crypto_clear: at %ld next %ld assoc ID %d\n", + current_time, peer->nextdate, peer->associd)); + #ifdef OPENSSL - key_expire(peer); + peer->assoc = 0; + peer->crypto = 0; + if (peer->pkey != NULL) EVP_PKEY_free(peer->pkey); - if (peer->ident_pkey != NULL) - EVP_PKEY_free(peer->ident_pkey); + peer->pkey = NULL; + + peer->digest = NULL; /* XXX MEMLEAK? check whether this needs to be freed in any way - never was freed */ + if (peer->subject != NULL) free(peer->subject); + peer->subject = NULL; + if (peer->issuer != NULL) free(peer->issuer); + peer->issuer = NULL; + + peer->pkeyid = 0; + + peer->pcookie = 0; + + if (peer->ident_pkey != NULL) + EVP_PKEY_free(peer->ident_pkey); + peer->ident_pkey = NULL; + + memset(&peer->fstamp, 0, sizeof(peer->fstamp)); + if (peer->iffval != NULL) BN_free(peer->iffval); + peer->iffval = NULL; + if (peer->grpkey != NULL) BN_free(peer->grpkey); - if (peer->cmmd != NULL) - free(peer->cmmd); + peer->grpkey = NULL; + value_free(&peer->cookval); value_free(&peer->recval); - value_free(&peer->tai_leap); + + if (peer->cmmd != NULL) { + free(peer->cmmd); + peer->cmmd = NULL; + } + + key_expire(peer); + value_free(&peer->encrypt); - value_free(&peer->sndval); #endif /* OPENSSL */ +} + +/* + * peer_clear - clear peer filter registers. See Section 3.4.8 of the spec. + */ +void +peer_clear( + struct peer *peer, /* peer structure */ + char *ident /* tally lights */ + ) +{ + int i; + + peer_crypto_clear(peer); + + if (peer == sys_peer) + sys_peer = NULL; /* * Wipe the association clean and initialize the nonzero values. */ memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO); - if (peer == sys_peer) - sys_peer = NULL; peer->estbdelay = sys_bdelay; - peer->hpoll = peer->kpoll = peer->minpoll; peer->ppoll = peer->maxpoll; - peer->jitter = MAXDISPERSE; - peer->epoch = current_time; + peer->hpoll = peer->minpoll; + peer->disp = MAXDISPERSE; + peer->jitter = LOGTOD(sys_precision); + for (i = 0; i < NTP_SHIFT; i++) { + peer->filter_order[i] = i; + peer->filter_disp[i] = MAXDISPERSE; + } #ifdef REFCLOCK if (!(peer->flags & FLAG_REFCLOCK)) { peer->leap = LEAP_NOTINSYNC; @@ -1521,43 +1580,25 @@ peer_clear( peer->leap = LEAP_NOTINSYNC; peer->stratum = STRATUM_UNSPEC; memcpy(&peer->refid, ident, 4); -#endif - for (i = 0; i < NTP_SHIFT; i++) { - peer->filter_order[i] = i; - peer->filter_disp[i] = MAXDISPERSE; - peer->filter_epoch[i] = current_time; - } +#endif /* REFCLOCK */ /* - * If he dies as a broadcast client, he comes back to life as - * a broadcast client in client mode in order to recover the - * initial autokey values. - */ - if (peer->cast_flags & MDF_BCLNT) { - peer->flags |= FLAG_MCAST; - peer->hmode = MODE_CLIENT; - } - - /* - * Randomize the first poll to avoid bunching, but only if the - * rascal has never been heard. During initialization use the - * association count to spread out the polls at one-second - * intervals. + * During initialization use the association count to spread out + * the polls at one-second intervals. Othersie, randomize over + * the minimum poll interval in order to avoid broadcast + * implosion. */ peer->nextdate = peer->update = peer->outdate = current_time; - peer->burst = 0; - if (oreach) - poll_update(peer, 0); - else if (initializing) - peer->nextdate = current_time + peer_associations; + if (initializing) + peer->nextdate += peer_associations; + else if (peer->hmode == MODE_PASSIVE) + peer->nextdate += RESP_DELAY; else - peer->nextdate = current_time + (u_int)RANDOM % - peer_associations; -#ifdef DEBUG - if (debug) - printf("peer_clear: at %ld assoc ID %d refid %s\n", - current_time, peer->associd, ident); -#endif + peer->nextdate += (ntp_random() & ((1 << NTP_MINDPOLL) - + 1)); + + DPRINTF(1, ("peer_clear: at %ld next %ld assoc ID %d refid %s\n", + current_time, peer->nextdate, peer->associd, ident)); } @@ -1576,7 +1617,7 @@ clock_filter( double dst[NTP_SHIFT]; /* distance vector */ int ord[NTP_SHIFT]; /* index vector */ int i, j, k, m; - double dsp, jit, dtemp, etemp; + double dtemp, etemp; /* * Shift the new sample into the register and discard the oldest @@ -1587,14 +1628,13 @@ clock_filter( * precision. The delay can sometimes swing negative due to * frequency skew, so it is clamped non-negative. */ - dsp = min(LOGTOD(peer->precision) + LOGTOD(sys_precision) + - sample_disp, MAXDISPERSE); j = peer->filter_nextpt; peer->filter_offset[j] = sample_offset; peer->filter_delay[j] = max(0, sample_delay); - peer->filter_disp[j] = dsp; - j++; j %= NTP_SHIFT; - peer->filter_nextpt = (u_short) j; + peer->filter_disp[j] = sample_disp; + peer->filter_epoch[j] = current_time; + j = (j + 1) % NTP_SHIFT; + peer->filter_nextpt = j; /* * Update dispersions since the last update and at the same @@ -1614,26 +1654,31 @@ clock_filter( dst[i] = MAXDISPERSE; else if (peer->update - peer->filter_epoch[j] > allan_xpt) - dst[i] = MAXDISTANCE + peer->filter_disp[j]; + dst[i] = sys_maxdist + peer->filter_disp[j]; else dst[i] = peer->filter_delay[j]; ord[i] = j; j++; j %= NTP_SHIFT; } - peer->filter_epoch[j] = current_time; /* - * Sort the samples in both lists by distance. - */ - for (i = 1; i < NTP_SHIFT; i++) { - for (j = 0; j < i; j++) { - if (dst[j] > dst[i]) { - k = ord[j]; - ord[j] = ord[i]; - ord[i] = k; - etemp = dst[j]; - dst[j] = dst[i]; - dst[i] = etemp; + * If the clock discipline has stabilized, sort the samples in + * both lists by distance. Note, we do not displace a higher + * distance sample by a lower distance one unless lower by at + * least the precision. + */ + if (state == 4) { + for (i = 1; i < NTP_SHIFT; i++) { + for (j = 0; j < i; j++) { + if (dst[j] > dst[i] + + LOGTOD(sys_precision)) { + k = ord[j]; + ord[j] = ord[i]; + ord[i] = k; + etemp = dst[j]; + dst[j] = dst[i]; + dst[i] = etemp; + } } } } @@ -1641,61 +1686,59 @@ clock_filter( /* * Copy the index list to the association structure so ntpq * can see it later. Prune the distance list to samples less - * than MAXDISTANCE, but keep at least two valid samples for + * than max distance, but keep at least two valid samples for * jitter calculation. */ m = 0; for (i = 0; i < NTP_SHIFT; i++) { peer->filter_order[i] = (u_char) ord[i]; if (dst[i] >= MAXDISPERSE || (m >= 2 && dst[i] >= - MAXDISTANCE)) + sys_maxdist)) continue; m++; } /* - * Compute the dispersion and jitter squares. The dispersion - * is weighted exponentially by NTP_FWEIGHT (0.5) so it is - * normalized close to 1.0. The jitter is the mean of the square - * differences relative to the lowest delay sample. If no - * acceptable samples remain in the shift register, quietly - * tiptoe home leaving only the dispersion. + * Compute the dispersion and jitter. The dispersion is weighted + * exponentially by NTP_FWEIGHT (0.5) so it is normalized close + * to 1.0. The jitter is the RMS differences relative to the + * lowest delay sample. If no acceptable samples remain in the + * shift register, quietly tiptoe home leaving only the + * dispersion. */ - jit = 0; - peer->disp = 0; + peer->disp = peer->jitter = 0; k = ord[0]; for (i = NTP_SHIFT - 1; i >= 0; i--) { - j = ord[i]; peer->disp = NTP_FWEIGHT * (peer->disp + peer->filter_disp[j]); if (i < m) - jit += DIFF(peer->filter_offset[j], + peer->jitter += DIFF(peer->filter_offset[j], peer->filter_offset[k]); } /* * If no acceptable samples remain in the shift register, * quietly tiptoe home leaving only the dispersion. Otherwise, - * save the offset, delay and jitter average. Note the jitter - * must not be less than the system precision. + * save the offset, delay and jitter. Note the jitter must not + * be less than the precision. */ if (m == 0) return; + etemp = fabs(peer->offset - peer->filter_offset[k]); - dtemp = sqrt(peer->jitter); peer->offset = peer->filter_offset[k]; peer->delay = peer->filter_delay[k]; if (m > 1) - jit /= m - 1; - peer->jitter = max(jit, SQUARE(LOGTOD(sys_precision))); + peer->jitter /= m - 1; + peer->jitter = max(SQRT(peer->jitter), LOGTOD(sys_precision)); /* * A new sample is useful only if it is younger than the last - * one used, but only if the sucker has been synchronized. + * one used. Note the order is FIFO if the clock discipline has + * not stabilized. */ - if (peer->filter_epoch[k] <= peer->epoch && sys_leap != - LEAP_NOTINSYNC) { + if (peer->filter_epoch[k] <= peer->epoch) { #ifdef DEBUG if (debug) printf("clock_filter: discard %lu\n", @@ -1710,9 +1753,9 @@ clock_filter( * last update is less than twice the system poll interval, * consider the update a popcorn spike and ignore it. */ - if (m > 1 && etemp > CLOCK_SGATE * dtemp && - (long)(peer->filter_epoch[k] - peer->epoch) < (1 << (sys_poll + - 1))) { + if (etemp > CLOCK_SGATE * peer->jitter && m > 1 && + peer->filter_epoch[k] - peer->epoch < 2. * + ULOGTOD(sys_poll)) { #ifdef DEBUG if (debug) printf("clock_filter: popcorn %.6f %.6f\n", @@ -1723,7 +1766,7 @@ clock_filter( /* * The mitigated sample statistics are saved for later - * processing. + * processing. If not in a burst, tickle the select. */ peer->epoch = peer->filter_epoch[k]; #ifdef DEBUG @@ -1731,8 +1774,10 @@ clock_filter( printf( "clock_filter: n %d off %.6f del %.6f dsp %.6f jit %.6f, age %lu\n", m, peer->offset, peer->delay, peer->disp, - SQRT(peer->jitter), peer->update - peer->epoch); + peer->jitter, current_time - peer->epoch); #endif + if (peer->burst == 0 || sys_leap == LEAP_NOTINSYNC) + clock_select(); } @@ -1751,14 +1796,13 @@ clock_select(void) int i, j, k, n; int nlist, nl3; - double d, e, f; - int allow, sw, osurv; + int allow, osurv; + double d, e, f, g; double high, low; - double synch[NTP_MAXCLOCK], error[NTP_MAXCLOCK]; + double synch[NTP_MAXASSOC], error[NTP_MAXASSOC]; struct peer *osys_peer; struct peer *typeacts = NULL; struct peer *typelocal = NULL; - struct peer *typepps = NULL; struct peer *typesystem = NULL; static int list_alloc = 0; @@ -1775,16 +1819,17 @@ clock_select(void) */ osys_peer = sys_peer; sys_peer = NULL; + sys_pps = NULL; + sys_prefer = NULL; osurv = sys_survivors; sys_survivors = 0; - sys_prefer = NULL; #ifdef LOCKCLOCK sys_leap = LEAP_NOTINSYNC; sys_stratum = STRATUM_UNSPEC; memcpy(&sys_refid, "DOWN", 4); #endif /* LOCKCLOCK */ nlist = 0; - for (n = 0; n < HASH_SIZE; n++) + for (n = 0; n < NTP_HASH_SIZE; n++) nlist += peer_hash_count[n]; if (nlist > list_alloc) { if (list_alloc > 0) { @@ -1798,9 +1843,9 @@ clock_select(void) indx_size += 5 * 3 * sizeof(*indx); peer_list_size += 5 * sizeof(*peer_list); } - endpoint = emalloc(endpoint_size); - indx = emalloc(indx_size); - peer_list = emalloc(peer_list_size); + endpoint = (struct endpoint *)emalloc(endpoint_size); + indx = (int *)emalloc(indx_size); + peer_list = (struct peer **)emalloc(peer_list_size); } /* @@ -1814,7 +1859,7 @@ clock_select(void) * bucks and collectively crank the chimes. */ nlist = nl3 = 0; /* none yet */ - for (n = 0; n < HASH_SIZE; n++) { + for (n = 0; n < NTP_HASH_SIZE; n++) { for (peer = peer_hash[n]; peer != NULL; peer = peer->next) { peer->flags &= ~FLAG_SYSPEER; @@ -1834,6 +1879,7 @@ clock_select(void) * nobody else is around. These guys are all * configured, so we never throw them away. */ +#ifdef REFCLOCK if (peer->refclktype == REFCLK_LOCALCLOCK #if defined(VMS) && defined(VMS_LOCALUNIT) /* wjm: VMS_LOCALUNIT taken seriously */ @@ -1842,11 +1888,9 @@ clock_select(void) #endif /* VMS && VMS_LOCALUNIT */ ) { typelocal = peer; +#ifndef LOCKCLOCK if (!(peer->flags & FLAG_PREFER)) continue; /* no local clock */ -#ifdef LOCKCLOCK - else - sys_prefer = peer; #endif /* LOCKCLOCK */ } if (peer->sstclktype == CTL_SST_TS_TELEPHONE) { @@ -1854,6 +1898,7 @@ clock_select(void) if (!(peer->flags & FLAG_PREFER)) continue; /* no acts */ } +#endif /* REFCLOCK */ /* * If we get this far, the peer can stay on the @@ -1873,6 +1918,7 @@ clock_select(void) for (i = nl3 - 1; i >= 0; i--) { if (e >= endpoint[indx[i]].val) break; + indx[i + 3] = indx[i]; } indx[i + 3] = nl3; @@ -1883,6 +1929,7 @@ clock_select(void) for (; i >= 0; i--) { if (e >= endpoint[indx[i]].val) break; + indx[i + 2] = indx[i]; } indx[i + 2] = nl3; @@ -1893,6 +1940,7 @@ clock_select(void) for (; i >= 0; i--) { if (e >= endpoint[indx[i]].val) break; + indx[i + 1] = indx[i]; } indx[i + 1] = nl3; @@ -1925,7 +1973,9 @@ clock_select(void) * correct synchronization is not possible. * * Here, nlist is the number of candidates and allow is the - * number of falsetickers. + * number of falsetickers. Upon exit, the truechimers are the + * susvivors with offsets not less than low and not greater than + * high. There may be none of them. */ low = 1e9; high = -1e9; @@ -1976,31 +2026,76 @@ clock_select(void) } /* + * Clustering algorithm. Construct candidate list in order first + * by stratum then by root distance, but keep only the best + * NTP_MAXASSOC of them. Scan the list to find falsetickers, who + * leave the island immediately. The TRUE peer is always a + * truechimer. We must leave at least one peer to collect the + * million bucks. If in orphan mode, rascals found with lower + * stratum are guaranteed a seat on the bus. + */ + j = 0; + for (i = 0; i < nlist; i++) { + peer = peer_list[i]; + if (nlist > 1 && (peer->offset <= low || peer->offset >= + high) && !(peer->flags & FLAG_TRUE) && + !(sys_stratum >= sys_orphan && peer->stratum < + sys_orphan)) + continue; + + peer->status = CTL_PST_SEL_DISTSYSPEER; + + /* + * The order metric is formed from the stratum times + * max distance (1.) plus the root distance. It strongly + * favors the lowest stratum, but a higher stratum peer + * can capture the clock if the low stratum dominant + * hasn't been heard for awhile. + */ + d = root_distance(peer) + peer->stratum * sys_maxdist; + if (j >= NTP_MAXASSOC) { + if (d >= synch[j - 1]) + continue; + else + j--; + } + for (k = j; k > 0; k--) { + if (d >= synch[k - 1]) + break; + + peer_list[k] = peer_list[k - 1]; + error[k] = error[k - 1]; + synch[k] = synch[k - 1]; + } + peer_list[k] = peer; + error[k] = peer->jitter; + synch[k] = d; + j++; + } + nlist = j; + + /* * If no survivors remain at this point, check if the local * clock or modem drivers have been found. If so, nominate one * of them as the only survivor. Otherwise, give up and leave * the island to the rats. */ - if (high <= low) { + if (nlist == 0) { if (typeacts != 0) { - typeacts->status = CTL_PST_SEL_SANE; + typeacts->status = CTL_PST_SEL_DISTSYSPEER; peer_list[0] = typeacts; nlist = 1; } else if (typelocal != 0) { - typelocal->status = CTL_PST_SEL_SANE; + typelocal->status = CTL_PST_SEL_DISTSYSPEER; peer_list[0] = typelocal; nlist = 1; } else { if (osys_peer != NULL) { - sys_poll = NTP_MINPOLL; NLOG(NLOG_SYNCSTATUS) msyslog(LOG_INFO, "no servers reachable"); report_event(EVNT_PEERSTCHG, NULL); } - if (osurv > 0) - resetmanycast(); - return; } } @@ -2010,91 +2105,27 @@ clock_select(void) * cast out one falsticker. For the Byzantine agreement * algorithm used here, that number is 4; however, the default * sys_minsane is 1 to speed initial synchronization. Careful - * operators will tinker the value to 4 and use at least that + * operators will tinker a higher value and use at least that * number of synchronization sources. */ if (nlist < sys_minsane) return; - /* - * Clustering algorithm. Construct candidate list in order first - * by stratum then by root distance, but keep only the best - * NTP_MAXCLOCK of them. Scan the list to find falsetickers, who - * leave the island immediately. If a falseticker is not - * configured, his association raft is drowned as well, but only - * if at at least eight poll intervals have gone. We must leave - * at least one peer to collect the million bucks. - * - * Note the hysteresis gimmick that increases the effective - * distance for those rascals that have not made the final cut. - * This is to discourage clockhopping. Note also the prejudice - * against lower stratum peers if the floor is elevated. - */ - j = 0; - for (i = 0; i < nlist; i++) { - peer = peer_list[i]; - if (nlist > 1 && (peer->offset <= low || peer->offset >= - high)) { - if (!(peer->flags & FLAG_CONFIG)) - unpeer(peer); - continue; - } - peer->status = CTL_PST_SEL_DISTSYSPEER; - d = peer->stratum; - if (d < sys_floor) - d += sys_floor; - if (d > sys_ceiling) - d = STRATUM_UNSPEC; - d = root_distance(peer) + d * MAXDISTANCE; - d *= 1. - peer->hyst; - if (j >= NTP_MAXCLOCK) { - if (d >= synch[j - 1]) - continue; - else - j--; - } - for (k = j; k > 0; k--) { - if (d >= synch[k - 1]) - break; - peer_list[k] = peer_list[k - 1]; - error[k] = error[k - 1]; - synch[k] = synch[k - 1]; - } - peer_list[k] = peer; - error[k] = peer->jitter; - synch[k] = d; - j++; - } - nlist = j; - if (nlist == 0) { -#ifdef DEBUG - if (debug) - printf("clock_select: empty intersection interval\n"); -#endif - return; - } - for (i = 0; i < nlist; i++) { + for (i = 0; i < nlist; i++) peer_list[i]->status = CTL_PST_SEL_SELCAND; -#ifdef DEBUG - if (debug > 2) - printf("select: %s distance %.6f jitter %.6f\n", - ntoa(&peer_list[i]->srcadr), synch[i], - SQRT(error[i])); -#endif - } - /* * Now, vote outlyers off the island by select jitter weighted - * by root dispersion. Continue voting as long as there are more - * than sys_minclock survivors and the minimum select jitter - * squared is greater than the maximum peer jitter squared. Stop - * if we are about to discard a prefer peer, who of course has - * the immunity idol. + * by root distance. Continue voting as long as there are more + * than sys_minclock survivors and the minimum select jitter is + * greater than the maximum peer jitter. Stop if we are about to + * discard a TRUE or PREFER peer, who of course has the + * immunity idol. */ while (1) { d = 1e9; e = -1e9; + f = g = 0; k = 0; for (i = 0; i < nlist; i++) { if (error[i] < d) @@ -2104,28 +2135,24 @@ clock_select(void) for (j = 0; j < nlist; j++) f += DIFF(peer_list[j]->offset, peer_list[i]->offset); - f /= nlist - 1; + f = SQRT(f / (nlist - 1)); } if (f * synch[i] > e) { - sys_selerr = f; + g = f; e = f * synch[i]; k = i; } } - f = max(sys_selerr, SQUARE(LOGTOD(sys_precision))); + f = max(f, LOGTOD(sys_precision)); if (nlist <= sys_minclock || f <= d || - peer_list[k]->flags & FLAG_PREFER) + peer_list[k]->flags & (FLAG_TRUE | FLAG_PREFER)) break; #ifdef DEBUG if (debug > 2) printf( "select: drop %s select %.6f jitter %.6f\n", - ntoa(&peer_list[k]->srcadr), - SQRT(sys_selerr), SQRT(d)); + ntoa(&peer_list[k]->srcadr), g, d); #endif - if (!(peer_list[k]->flags & FLAG_CONFIG) && - peer_list[k]->hmode == MODE_CLIENT) - unpeer(peer_list[k]); for (j = k + 1; j < nlist; j++) { peer_list[j - 1] = peer_list[j]; error[j - 1] = error[j]; @@ -2137,158 +2164,178 @@ clock_select(void) * What remains is a list usually not greater than sys_minclock * peers. We want only a peer at the lowest stratum to become * the system peer, although all survivors are eligible for the - * combining algorithm. First record their order, diddle the - * flags and clamp the poll intervals. Then, consider each peer - * in turn and OR the leap bits on the assumption that, if some - * of them honk nonzero bits, they must know what they are - * doing. Check for prefer and pps peers at any stratum. Check - * if the old system peer is among the peers at the lowest - * stratum. Note that the head of the list is at the lowest - * stratum and that unsynchronized peers cannot survive this - * far. - * - * Fiddle for hysteresis. Pump it up for a peer only if the peer - * stratum is at least the floor and there are enough survivors. - * This minimizes the pain when tossing out rascals beneath the - * floorboard. Don't count peers with stratum above the ceiling. - * Manycast is sooo complicated. - */ - leap_consensus = 0; - for (i = nlist - 1; i >= 0; i--) { + * combining algorithm. Consider each peer in turn and OR the + * leap bits on the assumption that, if some of them honk + * nonzero bits, they must know what they are doing. Check for + * prefer and pps peers at any stratum. Note that the head of + * the list is at the lowest stratum and that unsynchronized + * peers cannot survive this far. + */ + leap_next = 0; + for (i = 0; i < nlist; i++) { peer = peer_list[i]; - leap_consensus |= peer->leap; + sys_survivors++; + leap_next |= peer->leap; peer->status = CTL_PST_SEL_SYNCCAND; - peer->rank++; - peer->flags |= FLAG_SYSPEER; - if (peer->stratum >= sys_floor && osurv >= sys_minclock) - peer->hyst = HYST; - else - peer->hyst = 0; - if (peer->stratum <= sys_ceiling) - sys_survivors++; if (peer->flags & FLAG_PREFER) sys_prefer = peer; - if (peer->refclktype == REFCLK_ATOM_PPS && - peer->stratum < STRATUM_UNSPEC) - typepps = peer; - if (peer->stratum == peer_list[0]->stratum && peer == - osys_peer) + if (peer == osys_peer) typesystem = peer; +#ifdef REFCLOCK + if (peer->refclktype == REFCLK_ATOM_PPS) + sys_pps = peer; +#endif /* REFCLOCK */ +#if DEBUG + if (debug > 1) + printf("cluster: survivor %s metric %.6f\n", + ntoa(&peer_list[i]->srcadr), synch[i]); +#endif } /* - * In manycast client mode we may have spooked a sizeable number - * of peers that we don't need. If there are at least - * sys_minclock of them, the manycast message will be turned - * off. By the time we get here we nay be ready to prune some of - * them back, but we want to make sure all the candicates have - * had a chance. If they didn't pass the sanity and intersection - * tests, they have already been voted off the island. + * Anticlockhop provision. Keep the current system peer if it is + * a survivor but not first in the list. But do that only HOPPER + * times. */ - if (sys_survivors < sys_minclock && osurv >= sys_minclock) - resetmanycast(); + if (osys_peer == NULL || typesystem == NULL || typesystem == + peer_list[0] || sys_hopper > sys_maxhop) { + typesystem = peer_list[0]; + sys_hopper = 0; + } else { + peer->selbroken++; + } /* * Mitigation rules of the game. There are several types of - * peers that make a difference here: (1) prefer local peers - * (type REFCLK_LOCALCLOCK with FLAG_PREFER) or prefer modem - * peers (type REFCLK_NIST_ATOM etc with FLAG_PREFER), (2) pps - * peers (type REFCLK_ATOM_PPS), (3) remaining prefer peers - * (flag FLAG_PREFER), (4) the existing system peer, if any, (5) - * the head of the survivor list. Note that only one peer can be - * declared prefer. The order of preference is in the order - * stated. Note that all of these must be at the lowest stratum, - * i.e., the stratum of the head of the survivor list. - */ - if (sys_prefer) - sw = sys_prefer->refclktype == REFCLK_LOCALCLOCK || - sys_prefer->sstclktype == CTL_SST_TS_TELEPHONE || - !typepps; - else - sw = 0; - if (sw) { - sys_peer = sys_prefer; + * peers that can be selected here: (1) orphan, (2) prefer peer + * (flag FLAG_PREFER) (3) pps peers (type REFCLK_ATOM_PPS), (4) + * the existing system peer, if any, and (5) the head of the + * survivor list. + */ + if (typesystem->stratum >= sys_orphan) { + + /* + * If in orphan mode, choose the system peer. If the + * lowest distance, we are the orphan parent and the + * offset is zero. + */ + sys_peer = typesystem; sys_peer->status = CTL_PST_SEL_SYSPEER; - sys_offset = sys_peer->offset; - sys_syserr = sys_peer->jitter; + if (sys_orphandelay < sys_peer->rootdelay) { + sys_offset = 0; + sys_refid = htonl(LOOPBACKADR); + } else { + sys_offset = sys_peer->offset; + sys_refid = addr2refid(&sys_peer->srcadr); + } + sys_jitter = LOGTOD(sys_precision); #ifdef DEBUG if (debug > 1) - printf("select: prefer offset %.6f\n", + printf("select: orphan offset %.6f\n", sys_offset); #endif - } -#ifndef LOCKCLOCK - else if (typepps) { - sys_peer = typepps; - sys_peer->status = CTL_PST_SEL_PPS; - sys_offset = sys_peer->offset; - sys_syserr = sys_peer->jitter; - if (!pps_control) - NLOG(NLOG_SYSEVENT) - msyslog(LOG_INFO, "pps sync enabled"); - pps_control = current_time; + } else if (sys_prefer) { + + /* + * If a pps peer is present, choose it; otherwise, + * choose the prefer peer. + */ + if (sys_pps) { + sys_peer = sys_pps; + sys_peer->status = CTL_PST_SEL_PPS; + sys_offset = sys_peer->offset; + if (!pps_control) + NLOG(NLOG_SYSEVENT) + msyslog(LOG_INFO, + "pps sync enabled"); + pps_control = current_time; #ifdef DEBUG - if (debug > 1) - printf("select: pps offset %.6f\n", - sys_offset); + if (debug > 1) + printf("select: pps offset %.6f\n", + sys_offset); #endif - } else { - if (typesystem) - sys_peer = osys_peer; + } else { + sys_peer = sys_prefer; + sys_peer->status = CTL_PST_SEL_SYSPEER; + sys_offset = sys_peer->offset; +#ifdef DEBUG + if (debug > 1) + printf("select: prefer offset %.6f\n", + sys_offset); +#endif + } + if (sys_peer->stratum == STRATUM_REFCLOCK || + sys_peer->stratum == STRATUM_UNSPEC) + sys_refid = sys_peer->refid; else - sys_peer = peer_list[0]; + sys_refid = addr2refid(&sys_peer->srcadr); + sys_jitter = sys_peer->jitter; + } else { + + /* + * Otherwise, choose the anticlockhopper. + */ + sys_peer = typesystem; sys_peer->status = CTL_PST_SEL_SYSPEER; - sys_peer->rank++; - sys_offset = clock_combine(peer_list, nlist); - sys_syserr = sys_peer->jitter + sys_selerr; + clock_combine(peer_list, nlist); + if (sys_peer->stratum == STRATUM_REFCLOCK || + sys_peer->stratum == STRATUM_UNSPEC) + sys_refid = sys_peer->refid; + else + sys_refid = addr2refid(&sys_peer->srcadr); + sys_jitter = SQRT(SQUARE(sys_peer->jitter) + + SQUARE(sys_jitter)); #ifdef DEBUG if (debug > 1) printf("select: combine offset %.6f\n", sys_offset); #endif } -#endif /* LOCKCLOCK */ + + /* + * We have found the alpha male. + */ + sys_peer->flags |= FLAG_SYSPEER; if (osys_peer != sys_peer) { char *src; - if (sys_peer == NULL) - sys_peer_refid = 0; - else - sys_peer_refid = addr2refid(&sys_peer->srcadr); report_event(EVNT_PEERSTCHG, NULL); #ifdef REFCLOCK - if (ISREFCLOCKADR(&sys_peer->srcadr)) + if (sys_peer->flags & FLAG_REFCLOCK) src = refnumtoa(&sys_peer->srcadr); else -#endif +#endif /* REFCLOCK */ src = ntoa(&sys_peer->srcadr); NLOG(NLOG_SYNCSTATUS) - msyslog(LOG_INFO, "synchronized to %s, stratum=%d", src, - sys_peer->stratum); + msyslog(LOG_INFO, "synchronized to %s, stratum %d", + src, sys_peer->stratum); } clock_update(); } + /* - * clock_combine - combine offsets from selected peers + * clock_combine - compute system offset and jitter from selected peers */ -static double +static void clock_combine( - struct peer **peers, - int npeers + struct peer **peers, /* survivor list */ + int npeers /* number of survivors */ ) { int i; - double x, y, z; + double x, y, z, w; - y = z = 0; + y = z = w = 0; for (i = 0; i < npeers; i++) { x = root_distance(peers[i]); y += 1. / x; z += peers[i]->offset / x; + w += SQUARE(peers[i]->offset - peers[0]->offset) / x; } - return (z / y); + sys_offset = z / y; + sys_jitter = SQRT(w / y); } /* @@ -2299,14 +2346,22 @@ root_distance( struct peer *peer ) { + double dist; + /* * Careful squeak here. The value returned must be greater than - * zero blamed on the peer jitter, which must be at least the - * square of sys_precision. + * the minimum root dispersion in order to avoid clockhop with + * highly precise reference clocks. In orphan mode lose the peer + * root delay, as that is used by the election algorithm. */ - return ((peer->rootdelay + peer->delay) / 2 + + if (peer->stratum >= sys_orphan) + dist = 0; + else + dist = peer->rootdelay; + dist += max(sys_mindisp, dist + peer->delay) / 2 + peer->rootdispersion + peer->disp + clock_phi * - (current_time - peer->update) + SQRT(peer->jitter)); + (current_time - peer->update) + peer->jitter; + return (dist); } /* @@ -2319,20 +2374,62 @@ peer_xmit( { struct pkt xpkt; /* transmit packet */ int sendlen, authlen; - keyid_t xkeyid = 0; /* transmit key ID */ + keyid_t xkeyid = 0; /* transmit key ID */ l_fp xmt_tx; + if (!peer->dstadr) /* don't bother with peers without interface */ + return; + + /* + * This is deliciously complicated. There are three cases. + * + * case leap stratum refid delay dispersion + * + * normal system system system system system + * orphan child 00 orphan system orphan system + * orphan parent 00 orphan loopbk 0 0 + */ /* - * Initialize transmit packet header fields. + * This is a normal packet. Use the system variables. */ - xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, peer->version, - peer->hmode); - xpkt.stratum = STRATUM_TO_PKT(sys_stratum); + if (sys_stratum < sys_orphan) { + xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, + peer->version, peer->hmode); + xpkt.stratum = STRATUM_TO_PKT(sys_stratum); + xpkt.refid = sys_refid; + xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay)); + xpkt.rootdispersion = + HTONS_FP(DTOUFP(sys_rootdispersion)); + + /* + * This is a orphan child packet. The host is synchronized to an + * orphan parent. Show leap synchronized, orphan stratum, system + * reference ID, orphan root delay and system root dispersion. + */ + } else if (sys_peer != NULL) { + xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, + peer->version, peer->hmode); + xpkt.stratum = STRATUM_TO_PKT(sys_orphan); + xpkt.refid = htonl(LOOPBACKADR); + xpkt.rootdelay = HTONS_FP(DTOFP(sys_orphandelay)); + xpkt.rootdispersion = + HTONS_FP(DTOUFP(sys_rootdispersion)); + + /* + * This is an orphan parent. Show leap synchronized, orphan + * stratum, loopack reference ID and zero root delay and root + * dispersion. + */ + } else { + xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, + peer->version, peer->hmode); + xpkt.stratum = STRATUM_TO_PKT(sys_orphan); + xpkt.refid = sys_refid; + xpkt.rootdelay = 0; + xpkt.rootdispersion = 0; + } xpkt.ppoll = peer->hpoll; xpkt.precision = sys_precision; - xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay)); - xpkt.rootdispersion = HTONS_FP(DTOUFP(sys_rootdispersion)); - xpkt.refid = sys_refid; HTONL_FP(&sys_reftime, &xpkt.reftime); HTONL_FP(&peer->org, &xpkt.org); HTONL_FP(&peer->rec, &xpkt.rec); @@ -2342,23 +2439,25 @@ peer_xmit( * is authenticated and contains a MAC. If not, the transmitted * packet is not authenticated. * - * In the current I/O semantics the default interface is set - * until after receiving a packet and setting the right - * interface. So, the first packet goes out unauthenticated. - * That's why the really icky test next is here. + * It is most important when autokey is in use that the local + * interface IP address be known before the first packet is + * sent. Otherwise, it is not possible to compute a correct MAC + * the recipient will accept. Thus, the I/O semantics have to do + * a little more work. In particular, the wildcard interface + * might not be usable. */ sendlen = LEN_PKT_NOMAC; if (!(peer->flags & FLAG_AUTHENABLE)) { get_systime(&peer->xmt); HTONL_FP(&peer->xmt, &xpkt.xmt); sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl], - &xpkt, sendlen); + &xpkt, sendlen); peer->sent++; #ifdef DEBUG if (debug) printf("transmit: at %ld %s->%s mode %d\n", - current_time, stoa(&peer->dstadr->sin), - stoa(&peer->srcadr), peer->hmode); + current_time, peer->dstadr ? stoa(&peer->dstadr->sin) : "-", + stoa(&peer->srcadr), peer->hmode); #endif return; } @@ -2366,12 +2465,11 @@ peer_xmit( /* * The received packet contains a MAC, so the transmitted packet * must be authenticated. If autokey is enabled, fuss with the - * various modes; otherwise, private key cryptography is used. + * various modes; otherwise, symmetric key cryptography is used. */ #ifdef OPENSSL if (crypto_flags && (peer->flags & FLAG_SKEY)) { struct exten *exten; /* extension field */ - u_int opcode; /* * The Public Key Dance (PKD): Cryptographic credentials @@ -2428,25 +2526,23 @@ peer_xmit( key_expire(peer); } peer->keyid = xkeyid; + exten = NULL; switch (peer->hmode) { - /* - * In broadcast server mode the autokey values are - * required by the broadcast clients. Push them when a - * new keylist is generated; otherwise, push the - * association message so the client can request them at - * other times. - */ + /* + * In broadcast server mode the autokey values are + * required by the broadcast clients. Push them when a + * new keylist is generated; otherwise, push the + * association message so the client can request them at + * other times. + */ case MODE_BROADCAST: if (peer->flags & FLAG_ASSOC) exten = crypto_args(peer, CRYPTO_AUTO | - CRYPTO_RESP, NULL); + CRYPTO_RESP, NULL); else exten = crypto_args(peer, CRYPTO_ASSOC | - CRYPTO_RESP, NULL); - sendlen += crypto_xmit(&xpkt, &peer->srcadr, - sendlen, exten, 0); - free(exten); + CRYPTO_RESP, NULL); break; /* @@ -2457,25 +2553,22 @@ peer_xmit( * synchronized, so the agreement must be postponed * until then. In any case, if a new keylist is * generated, the autokey values are pushed. + * + * If the crypto bit is lit, don't send requests. */ case MODE_ACTIVE: case MODE_PASSIVE: - if (peer->cmmd != NULL) { - peer->cmmd->associd = - htonl(peer->associd); - sendlen += crypto_xmit(&xpkt, - &peer->srcadr, sendlen, peer->cmmd, - 0); - free(peer->cmmd); - peer->cmmd = NULL; - } - exten = NULL; + if (peer->flash & TEST9) + break; + /* + * Parameter and certificate. + */ if (!peer->crypto) exten = crypto_args(peer, CRYPTO_ASSOC, - sys_hostname); + sys_hostname); else if (!(peer->crypto & CRYPTO_FLAG_VALID)) exten = crypto_args(peer, CRYPTO_CERT, - peer->issuer); + peer->issuer); /* * Identity. Note we have to sign the @@ -2483,12 +2576,13 @@ peer_xmit( * deadlock when the passive peer is walking the * certificate trail. Awesome. */ - else if ((opcode = crypto_ident(peer)) != 0) - exten = crypto_args(peer, opcode, NULL); + else if (!(peer->crypto & CRYPTO_FLAG_VRFY)) + exten = crypto_args(peer, + crypto_ident(peer), NULL); else if (sys_leap != LEAP_NOTINSYNC && - !(peer->crypto & CRYPTO_FLAG_SIGN)) + !(peer->crypto & CRYPTO_FLAG_SIGN)) exten = crypto_args(peer, CRYPTO_SIGN, - sys_hostname); + sys_hostname); /* * Autokey. We request the cookie only when the @@ -2501,32 +2595,27 @@ peer_xmit( * the autokey values without being asked. */ else if (sys_leap != LEAP_NOTINSYNC && - peer->leap != LEAP_NOTINSYNC && - !(peer->crypto & CRYPTO_FLAG_AGREE)) + peer->leap != LEAP_NOTINSYNC && + !(peer->crypto & CRYPTO_FLAG_AGREE)) exten = crypto_args(peer, CRYPTO_COOK, - NULL); + NULL); else if (peer->flags & FLAG_ASSOC) exten = crypto_args(peer, CRYPTO_AUTO | - CRYPTO_RESP, NULL); + CRYPTO_RESP, NULL); else if (!(peer->crypto & CRYPTO_FLAG_AUTO)) exten = crypto_args(peer, CRYPTO_AUTO, - NULL); + NULL); /* * Postamble. We trade leapseconds only when the * server and client are synchronized. */ else if (sys_leap != LEAP_NOTINSYNC && - peer->leap != LEAP_NOTINSYNC && - peer->crypto & CRYPTO_FLAG_TAI && - !(peer->crypto & CRYPTO_FLAG_LEAP)) + peer->leap != LEAP_NOTINSYNC && + peer->crypto & CRYPTO_FLAG_TAI && + !(peer->crypto & CRYPTO_FLAG_LEAP)) exten = crypto_args(peer, CRYPTO_TAI, - NULL); - if (exten != NULL) { - sendlen += crypto_xmit(&xpkt, - &peer->srcadr, sendlen, exten, 0); - free(exten); - } + NULL); break; /* @@ -2546,85 +2635,117 @@ peer_xmit( * requests them and the protocol blinds it using the * agreed key. It is a protocol error if the client has * the parameters but the server does not. + * + * If the crypto bit is lit, don't send requests. */ case MODE_CLIENT: - if (peer->cmmd != NULL) { - peer->cmmd->associd = - htonl(peer->associd); - sendlen += crypto_xmit(&xpkt, - &peer->srcadr, sendlen, peer->cmmd, - 0); - free(peer->cmmd); - peer->cmmd = NULL; - } - exten = NULL; + if (peer->flash & TEST9) + break; + /* + * Parameter and certificate. + */ if (!peer->crypto) exten = crypto_args(peer, CRYPTO_ASSOC, - sys_hostname); + sys_hostname); else if (!(peer->crypto & CRYPTO_FLAG_VALID)) exten = crypto_args(peer, CRYPTO_CERT, - peer->issuer); + peer->issuer); /* - * Identity. + * Identity */ - else if ((opcode = crypto_ident(peer)) != 0) - exten = crypto_args(peer, opcode, NULL); + else if (!(peer->crypto & CRYPTO_FLAG_VRFY)) + exten = crypto_args(peer, + crypto_ident(peer), NULL); /* * Autokey */ else if (!(peer->crypto & CRYPTO_FLAG_AGREE)) exten = crypto_args(peer, CRYPTO_COOK, - NULL); + NULL); else if (!(peer->crypto & CRYPTO_FLAG_AUTO) && - (peer->cast_flags & MDF_BCLNT)) + (peer->cast_flags & MDF_BCLNT)) exten = crypto_args(peer, CRYPTO_AUTO, - NULL); + NULL); /* * Postamble. We can sign the certificate here, * since there is no chance of deadlock. */ else if (sys_leap != LEAP_NOTINSYNC && - !(peer->crypto & CRYPTO_FLAG_SIGN)) + !(peer->crypto & CRYPTO_FLAG_SIGN)) exten = crypto_args(peer, CRYPTO_SIGN, - sys_hostname); + sys_hostname); else if (sys_leap != LEAP_NOTINSYNC && - peer->crypto & CRYPTO_FLAG_TAI && - !(peer->crypto & CRYPTO_FLAG_LEAP)) + peer->crypto & CRYPTO_FLAG_TAI && + !(peer->crypto & CRYPTO_FLAG_LEAP)) exten = crypto_args(peer, CRYPTO_TAI, - NULL); - if (exten != NULL) { - sendlen += crypto_xmit(&xpkt, - &peer->srcadr, sendlen, exten, 0); - free(exten); - } + NULL); break; } /* + * Build the extension fields as directed. A response to + * a request is always sent, even if an error. If an + * error occurs when sending a request, the crypto + * machinery broke or was misconfigured. In that case + * light the crypto bit to suppress further requests. + */ + if (peer->cmmd != NULL) { + peer->cmmd->associd = htonl(peer->associd); + sendlen += crypto_xmit(&xpkt, &peer->srcadr, + sendlen, peer->cmmd, 0); + free(peer->cmmd); + peer->cmmd = NULL; + } + if (exten != NULL) { + int ltemp = 0; + + if (exten->opcode != 0) { + ltemp = crypto_xmit(&xpkt, + &peer->srcadr, sendlen, exten, 0); + if (ltemp == 0) { + peer->flash |= TEST9; /* crypto error */ + free(exten); + return; + } + } + sendlen += ltemp; + free(exten); + } + + /* * If extension fields are present, we must use a - * private value of zero and force min poll interval. - * Most intricate. + * private cookie value of zero. Don't send if the + * crypto bit is set and no extension field is present, + * but in that case give back the key. Most intricate. */ - if (sendlen > LEN_PKT_NOMAC) + if (sendlen > LEN_PKT_NOMAC) { session_key(&peer->dstadr->sin, &peer->srcadr, xkeyid, 0, 2); + } else if (peer->flash & TEST9) { + authtrust(xkeyid, 0); + return; + } } #endif /* OPENSSL */ + + /* + * Stash the transmit timestamp corrected for the encryption + * delay. If autokey, give back the key, as we use keys only + * once. Check for errors such as missing keys, buffer overflow, + * etc. + */ xkeyid = peer->keyid; get_systime(&peer->xmt); L_ADD(&peer->xmt, &sys_authdelay); HTONL_FP(&peer->xmt, &xpkt.xmt); authlen = authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen); if (authlen == 0) { - msyslog(LOG_INFO, - "transmit: encryption key %d not found", xkeyid); - if (peer->flags & FLAG_CONFIG) - peer_clear(peer, "NKEY"); - else - unpeer(peer); + msyslog(LOG_INFO, "transmit: %s key %u not found", + stoa(&peer->srcadr), xkeyid); + peer->flash |= TEST9; /* no key found */ return; } sendlen += authlen; @@ -2638,7 +2759,7 @@ peer_xmit( exit (-1); } sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl], &xpkt, - sendlen); + sendlen); /* * Calculate the encryption delay. Keep the minimum over @@ -2657,19 +2778,19 @@ peer_xmit( #ifdef DEBUG if (debug) printf( - "transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d index %d\n", - current_time, ntoa(&peer->dstadr->sin), - ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen - - authlen, authlen, peer->keynumber); + "transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d index %d\n", + current_time, peer->dstadr ? ntoa(&peer->dstadr->sin) : "-", + ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen - + authlen, authlen, peer->keynumber); #endif #else #ifdef DEBUG if (debug) printf( - "transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d\n", - current_time, ntoa(&peer->dstadr->sin), - ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen - - authlen, authlen); + "transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d\n", + current_time, peer->dstadr ? ntoa(&peer->dstadr->sin) : "-", + ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen - + authlen, authlen); #endif #endif /* OPENSSL */ } @@ -2699,54 +2820,91 @@ fast_xmit( /* * Initialize transmit packet header fields from the receive * buffer provided. We leave some fields intact as received. If - * the gazinta was from a multicast address, the gazouta must go - * out another way. + * the gazinta was from a multicast address, the gazoutta must + * go out another way. + * + * The root delay field is special. If the system stratum is + * less than the orphan stratum, send the real root delay. + * Otherwise, if there is no system peer, send the orphan delay. + * Otherwise, we must be an orphan parent, so send zero. */ rpkt = &rbufp->recv_pkt; - if (rbufp->dstadr->flags & INT_MULTICAST) + if (rbufp->dstadr->flags & INT_MCASTOPEN) rbufp->dstadr = findinterface(&rbufp->recv_srcadr); /* - * If the packet has picked up a restriction due to either - * access denied or rate exceeded, decide what to do with it. + * This is deliciously complicated. There are four cases. + * + * case leap stratum refid delay dispersion + * + * KoD 11 16 KISS system system + * normal system system system system system + * orphan child 00 orphan system orphan system + * orphan parent 00 orphan loopbk 0 0 */ - if (mask & (RES_DONTTRUST | RES_LIMITED)) { - char *code = "????"; - - if (mask & RES_LIMITED) { - sys_limitrejected++; - code = "RATE"; - } else if (mask & RES_DONTTRUST) { - sys_restricted++; - code = "DENY"; - } - - /* - * Here we light up a kiss-of-death packet. Note the - * rate limit on these packets. Once a second initialize - * a bucket counter. Every packet sent decrements the - * counter until reaching zero. If the counter is zero, - * drop the kod. - */ + /* + * This is a kiss-of-death (KoD) packet. Show leap + * unsynchronized, stratum zero, reference ID the four-character + * kiss code and system root delay. Note the rate limit on these + * packets. Once a second initialize a bucket counter. Every + * packet sent decrements the counter until reaching zero. If + * the counter is zero, drop the kiss. + */ + if (mask & RES_LIMITED) { + sys_limitrejected++; if (sys_kod == 0 || !(mask & RES_DEMOBILIZE)) return; sys_kod--; - memcpy(&xpkt.refid, code, 4); xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC, PKT_VERSION(rpkt->li_vn_mode), xmode); xpkt.stratum = STRATUM_UNSPEC; - } else { + memcpy(&xpkt.refid, "RATE", 4); + xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay)); + xpkt.rootdispersion = + HTONS_FP(DTOUFP(sys_rootdispersion)); + + /* + * This is a normal packet. Use the system variables. + */ + } else if (sys_stratum < sys_orphan) { xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, PKT_VERSION(rpkt->li_vn_mode), xmode); xpkt.stratum = STRATUM_TO_PKT(sys_stratum); xpkt.refid = sys_refid; + xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay)); + xpkt.rootdispersion = + HTONS_FP(DTOUFP(sys_rootdispersion)); + + /* + * This is a orphan child packet. The host is synchronized to an + * orphan parent. Show leap synchronized, orphan stratum, system + * reference ID and orphan root delay. + */ + } else if (sys_peer != NULL) { + xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, + PKT_VERSION(rpkt->li_vn_mode), xmode); + xpkt.stratum = STRATUM_TO_PKT(sys_orphan); + xpkt.refid = sys_refid; + xpkt.rootdelay = HTONS_FP(DTOFP(sys_orphandelay)); + xpkt.rootdispersion = + HTONS_FP(DTOUFP(sys_rootdispersion)); + + /* + * This is an orphan parent. Show leap synchronized, orphan + * stratum, loopack reference ID and zero root delay. + */ + } else { + xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, + PKT_VERSION(rpkt->li_vn_mode), xmode); + xpkt.stratum = STRATUM_TO_PKT(sys_orphan); + xpkt.refid = htonl(LOOPBACKADR); + xpkt.rootdelay = HTONS_FP(DTOFP(0)); + xpkt.rootdispersion = HTONS_FP(DTOFP(0)); } xpkt.ppoll = rpkt->ppoll; xpkt.precision = sys_precision; - xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay)); - xpkt.rootdispersion = - HTONS_FP(DTOUFP(sys_rootdispersion)); + xpkt.rootdispersion = HTONS_FP(DTOUFP(sys_rootdispersion)); HTONL_FP(&sys_reftime, &xpkt.reftime); xpkt.org = rpkt->xmt; HTONL_FP(&rbufp->recv_time, &xpkt.rec); @@ -2773,11 +2931,11 @@ fast_xmit( /* * The received packet contains a MAC, so the transmitted packet - * must be authenticated. For private-key cryptography, use the - * predefined private keys to generate the cryptosum. For - * autokey cryptography, use the server private value to - * generate the cookie, which is unique for every source- - * destination-key ID combination. + * must be authenticated. For symmetric key cryptography, use + * the predefined and trusted symmetric keys to generate the + * cryptosum. For autokey cryptography, use the server private + * value to generate the cookie, which is unique for every + * source-destination-key ID combination. */ #ifdef OPENSSL if (xkeyid > NTP_MAXKEY) { @@ -2794,8 +2952,8 @@ fast_xmit( */ cookie = session_key(&rbufp->recv_srcadr, &rbufp->dstadr->sin, 0, sys_private, 0); - if (rbufp->recv_length >= (int)(sendlen + MAX_MAC_LEN + 2 * - sizeof(u_int32))) { + if (rbufp->recv_length >= (int)(sendlen + MAX_MAC_LEN + + 2 * sizeof(u_int32))) { session_key(&rbufp->dstadr->sin, &rbufp->recv_srcadr, xkeyid, 0, 2); temp32 = CRYPTO_RESP; @@ -2879,23 +3037,60 @@ key_expire( * Determine if the peer is unfit for synchronization * * A peer is unfit for synchronization if - * > not reachable - * > a synchronization loop would form - * > never been synchronized - * > stratum undefined or too high - * > too long without synchronization - * > designated noselect + * > TEST10 bad leap or stratum below floor or at or above ceiling + * > TEST11 root distance exceeded + * > TEST12 a direct or indirect synchronization loop would form + * > TEST13 unreachable or noselect */ -static int /* 0 if no, 1 if yes */ +int /* FALSE if fit, TRUE if unfit */ peer_unfit( struct peer *peer /* peer structure pointer */ ) { - return (!peer->reach || (peer->stratum > 1 && peer->refid == - peer->dstadr->addr_refid) || peer->leap == LEAP_NOTINSYNC || - peer->stratum >= STRATUM_UNSPEC || root_distance(peer) >= - MAXDISTANCE + 2. * clock_phi * ULOGTOD(sys_poll) || - peer->flags & FLAG_NOSELECT ); + int rval = 0; + + /* + * A stratum error occurs if (1) the server has never been + * synchronized, (2) the server stratum is below the floor or + * greater than or equal to the ceiling, (3) the system stratum + * is below the orphan stratum and the server stratum is greater + * than or equal to the orphan stratum. + */ + if (peer->leap == LEAP_NOTINSYNC || peer->stratum < sys_floor || + peer->stratum >= sys_ceiling || (sys_stratum < sys_orphan && + peer->stratum >= sys_orphan)) + rval |= TEST10; /* stratum out of bounds */ + + /* + * A distance error occurs if the root distance is greater than + * or equal to the distance threshold plus the increment due to + * one poll interval. + */ + if (root_distance(peer) >= sys_maxdist + clock_phi * + ULOGTOD(sys_poll)) + rval |= TEST11; /* distance exceeded */ + + /* + * A loop error occurs if the remote peer is synchronized to the + * local peer of if the remote peer is synchronized to the same + * server as the local peer, but only if the remote peer is not + * the orphan parent. + */ + if (peer->stratum > 1 && peer->refid != htonl(LOOPBACKADR) && + ((!peer->dstadr || peer->refid == peer->dstadr->addr_refid) || + peer->refid == sys_refid)) + rval |= TEST12; /* synch loop */ + + /* + * An unreachable error occurs if the server is unreachable or + * the noselect bit is set. + */ + if (!peer->reach || peer->flags & FLAG_NOSELECT) + rval |= TEST13; /* unreachable */ + + peer->flash &= ~PEER_TEST_MASK; + peer->flash |= rval; + return (rval); } @@ -2908,7 +3103,7 @@ peer_unfit( /* * This routine calculates the system precision, defined as the minimum - * of a sequency of differences between successive readings of the + * of a sequence of differences between successive readings of the * system clock. However, if the system clock can be read more than once * during a tick interval, the difference can be zero or one LSB unit, * where the LSB corresponds to one nanosecond or one microsecond. @@ -2992,6 +3187,8 @@ init_proto(void) sys_precision = (s_char)default_get_precision(); sys_jitter = LOGTOD(sys_precision); sys_rootdelay = 0; + sys_orphandelay = (double)(ntp_random() & 0xffff) / 65536. * + sys_maxdist; sys_rootdispersion = 0; L_CLR(&sys_reftime); sys_peer = NULL; @@ -3074,14 +3271,21 @@ proto_config( break; /* - * Turn on/off facility to listen to broadcasts. + * Turn on/off enable broadcasts. */ case PROTO_BROADCLIENT: sys_bclient = (int)value; - if (value) - io_setbclient(); - else + if (sys_bclient == 0) io_unsetbclient(); + else + io_setbclient(); + break; + + /* + * Turn on/off PPS discipline. + */ + case PROTO_PPS: + pps_enable = (int)value; break; /* @@ -3090,6 +3294,7 @@ proto_config( case PROTO_MULTICAST_ADD: if (svalue) io_multicast_add(*svalue); + sys_bclient = 1; break; /* @@ -3115,60 +3320,97 @@ proto_config( break; /* - * Require authentication to mobilize ephemeral associations. + * Turn on/off authentication to mobilize ephemeral + * associations. */ case PROTO_AUTHENTICATE: sys_authenticate = (int)value; break; /* - * Turn on/off PPS discipline. + * Set minimum number of survivors. */ - case PROTO_PPS: - pps_enable = (int)value; + case PROTO_MINCLOCK: + sys_minclock = (int)dvalue; break; /* - * Set the minimum number of survivors. + * Set maximum number of preemptable associations. */ - case PROTO_MINCLOCK: - sys_minclock = (int)dvalue; + case PROTO_MAXCLOCK: + sys_maxclock = (int)dvalue; break; /* - * Set the minimum number of candidates. + * Set minimum number of survivors. */ case PROTO_MINSANE: sys_minsane = (int)dvalue; break; /* - * Set the stratum floor. + * Set stratum floor. */ case PROTO_FLOOR: sys_floor = (int)dvalue; break; /* - * Set the stratum ceiling. + * Set stratum ceiling. */ case PROTO_CEILING: sys_ceiling = (int)dvalue; break; /* - * Set the cohort switch. + * Set orphan stratum. + */ + case PROTO_ORPHAN: + sys_orphan = (int)dvalue; + break; + + /* + * Set cohort switch. */ case PROTO_COHORT: - sys_cohort= (int)dvalue; + sys_cohort = (int)dvalue; + break; + + /* + * Set minimum dispersion increment. + */ + case PROTO_MINDISP: + sys_mindisp = dvalue; break; + /* - * Set the adjtime() resolution (s). + * Set maximum distance (select threshold). + */ + case PROTO_MAXDIST: + sys_maxdist = dvalue; + break; + + /* + * Set anticlockhop threshold. + */ + case PROTO_MAXHOP: + sys_maxhop = (int)dvalue; + break; + + /* + * Set adjtime() resolution (s). */ case PROTO_ADJ: sys_tick = dvalue; break; + /* + * Set manycast beacon interval. + */ + case PROTO_BEACON: + sys_beacon = (int)dvalue; + break; + #ifdef REFCLOCK /* * Turn on/off refclock calibrate @@ -3176,15 +3418,15 @@ proto_config( case PROTO_CAL: cal_enable = (int)value; break; -#endif +#endif /* REFCLOCK */ default: /* * Log this error. */ msyslog(LOG_INFO, - "proto_config: illegal item %d, value %ld", - item, value); + "proto_config: illegal item %d, value %ld", item, + value); } } |