diff options
Diffstat (limited to 'ntpd/ntp_proto.c')
| -rw-r--r-- | ntpd/ntp_proto.c | 306 |
1 files changed, 252 insertions, 54 deletions
diff --git a/ntpd/ntp_proto.c b/ntpd/ntp_proto.c index eb663515b8a4..33e97ef9d989 100644 --- a/ntpd/ntp_proto.c +++ b/ntpd/ntp_proto.c @@ -15,6 +15,7 @@ #include "ntp_control.h" #include "ntp_string.h" #include "ntp_leapsec.h" +#include "ntp_psl.h" #include "refidsmear.h" #include "lib_strbuf.h" @@ -31,6 +32,13 @@ # define BDELAY_DEFAULT (-0.050) #endif +#define SRVFUZ_SHIFT 6 /* 64 seconds */ +#define SRVRSP_FUZZ(x) \ + do { \ + x.l_uf &= 0; \ + x.l_ui &= ~((1 << SRVFUZ_SHIFT) - 1U); \ + } while(0) + /* * This macro defines the authentication state. If x is 1 authentication * is required; otherwise it is optional. @@ -79,6 +87,11 @@ nak_error_codes { #define POOL_SOLICIT_WINDOW 8 /* + * flag bits propagated from pool to individual peers + */ +#define POOL_FLAG_PMASK (FLAG_IBURST | FLAG_NOSELECT) + +/* * peer_select groups statistics for a peer used by clock_select() and * clock_cluster(). */ @@ -97,10 +110,16 @@ u_char sys_leap; /* system leap indicator, use set_sys_leap() to change this */ u_char xmt_leap; /* leap indicator sent in client requests, set up by set_sys_leap() */ u_char sys_stratum; /* system stratum */ s_char sys_precision; /* local clock precision (log2 s) */ -double sys_rootdelay; /* roundtrip delay to primary source */ -double sys_rootdisp; /* dispersion to primary source */ +double sys_rootdelay; /* roundtrip delay to root (primary source) */ +double sys_rootdisp; /* dispersion to root (primary source) */ +double prev_rootdisp; /* previous root dispersion */ +double p2_rootdisp; /* previous previous root dispersion */ u_int32 sys_refid; /* reference id (network byte order) */ l_fp sys_reftime; /* last update time */ +l_fp prev_reftime; /* previous sys_reftime */ +l_fp p2_reftime; /* previous previous sys_reftime */ +u_long prev_time; /* "current_time" when saved prev_time */ +u_long p2_time; /* previous prev_time */ struct peer *sys_peer; /* current peer */ #ifdef LEAP_SMEAR @@ -337,11 +356,18 @@ valid_NAK( /* * The ORIGIN must match, or this cannot be a valid NAK, either. */ + + if (FLAG_LOOPNONCE & peer->flags) { + myorg = &peer->nonce; + } else { + if (peer->flip > 0) { + myorg = &peer->borg; + } else { + myorg = &peer->aorg; + } + } + NTOHL_FP(&rpkt->org, &p_org); - if (peer->flip > 0) - myorg = &peer->borg; - else - myorg = &peer->aorg; if (L_ISZERO(&p_org) || L_ISZERO( myorg) || @@ -387,7 +413,7 @@ transmit( */ if (peer->cast_flags & (MDF_BCAST | MDF_MCAST)) { peer->outdate = current_time; - poll_update(peer, hpoll); + poll_update(peer, hpoll, 0); if (sys_leap != LEAP_NOTINSYNC) peer_xmit(peer); return; @@ -408,7 +434,7 @@ transmit( */ if (peer->cast_flags & MDF_ACAST) { peer->outdate = current_time; - poll_update(peer, hpoll); + poll_update(peer, hpoll, 0); if (peer->unreach > sys_beacon) { peer->unreach = 0; peer->ttl = 0; @@ -437,7 +463,7 @@ transmit( */ if (peer->cast_flags & MDF_POOL) { peer->outdate = current_time; - poll_update(peer, hpoll); + poll_update(peer, hpoll, 0); if ( (peer_associations <= 2 * sys_maxclock) && ( peer_associations < sys_maxclock || sys_survivors < sys_minclock)) @@ -549,7 +575,7 @@ transmit( /* * Do not transmit if in broadcast client mode. */ - poll_update(peer, hpoll); + poll_update(peer, hpoll, (peer->hmode == MODE_CLIENT)); if (peer->hmode != MODE_BCLIENT) peer_xmit(peer); @@ -640,31 +666,20 @@ receive( */ /* * Bogus port check is before anything, since it probably - * reveals a clogging attack. + * reveals a clogging attack. Likewise the mimimum packet size + * of 2 bytes (for mode 6/7) must be checked first. */ sys_received++; - if (0 == SRCPORT(&rbufp->recv_srcadr)) { + if (0 == SRCPORT(&rbufp->recv_srcadr) || rbufp->recv_length < 2) { sys_badlength++; - return; /* bogus port */ + return; /* bogus port / length */ } restrictions(&rbufp->recv_srcadr, &r4a); restrict_mask = r4a.rflags; 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); - DPRINTF(1, ("receive: at %ld %s<-%s ippeerlimit %d mode %d iflags %s restrict %s org %#010x.%08x xmt %#010x.%08x\n", - current_time, stoa(&rbufp->dstadr->sin), - stoa(&rbufp->recv_srcadr), r4a.ippeerlimit, hismode, - build_iflags(rbufp->dstadr->flags), - build_rflags(restrict_mask), - ntohl(pkt->org.l_ui), ntohl(pkt->org.l_uf), - ntohl(pkt->xmt.l_ui), ntohl(pkt->xmt.l_uf))); - - /* See basic mode and broadcast checks, below */ - INSIST(0 != hisstratum); if (restrict_mask & RES_IGNORE) { DPRINTF(2, ("receive: drop: RES_IGNORE\n")); @@ -696,6 +711,30 @@ receive( return; /* no time serve */ } + + /* If we arrive here, we should have a standard NTP packet. We + * check that the minimum size is available and fetch some more + * items from the packet once we can be sure they are indeed + * there. + */ + if (rbufp->recv_length < LEN_PKT_NOMAC) { + sys_badlength++; + return; /* bogus length */ + } + + hisleap = PKT_LEAP(pkt->li_vn_mode); + hisstratum = PKT_TO_STRATUM(pkt->stratum); + INSIST(0 != hisstratum); /* paranoia check PKT_TO_STRATUM result */ + + DPRINTF(1, ("receive: at %ld %s<-%s ippeerlimit %d mode %d iflags %s " + "restrict %s org %#010x.%08x xmt %#010x.%08x\n", + current_time, stoa(&rbufp->dstadr->sin), + stoa(&rbufp->recv_srcadr), r4a.ippeerlimit, hismode, + build_iflags(rbufp->dstadr->flags), + build_rflags(restrict_mask), + ntohl(pkt->org.l_ui), ntohl(pkt->org.l_uf), + ntohl(pkt->xmt.l_ui), ntohl(pkt->xmt.l_uf))); + /* * This is for testing. If restricted drop ten percent of * surviving packets. @@ -888,12 +927,13 @@ receive( } return; /* rate exceeded */ } - if (hismode == MODE_CLIENT) + if (hismode == MODE_CLIENT) { fast_xmit(rbufp, MODE_SERVER, skeyid, restrict_mask); - else + } else { fast_xmit(rbufp, MODE_ACTIVE, skeyid, restrict_mask); + } return; /* rate exceeded */ } restrict_mask &= ~RES_KOD; @@ -1250,9 +1290,11 @@ receive( if (AUTH(restrict_mask & RES_DONTTRUST, is_authentic)) { + /* Bug 3596: Do we want to fuzz the reftime? */ fast_xmit(rbufp, MODE_SERVER, skeyid, restrict_mask); } else if (is_authentic == AUTH_ERROR) { + /* Bug 3596: Do we want to fuzz the reftime? */ fast_xmit(rbufp, MODE_SERVER, 0, restrict_mask); sys_badauth++; @@ -1318,6 +1360,7 @@ receive( pkt->refid, rbufp->recv_length - MIN_V4_PKT_LEN, (u_char *)&pkt->exten); + /* Bug 3596: Do we want to fuzz the reftime? */ fast_xmit(rbufp, MODE_SERVER, skeyid, restrict_mask); } @@ -1386,8 +1429,8 @@ receive( peer = newpeer(&rbufp->recv_srcadr, NULL, rbufp->dstadr, r4a.ippeerlimit, MODE_CLIENT, hisversion, peer2->minpoll, peer2->maxpoll, - FLAG_PREEMPT | (FLAG_IBURST & peer2->flags), - MDF_UCAST | MDF_UCLNT, 0, skeyid, sys_ident); + (FLAG_PREEMPT | (POOL_FLAG_PMASK & peer2->flags)), + (MDF_UCAST | MDF_UCLNT), 0, skeyid, sys_ident); if (NULL == peer) { DPRINTF(2, ("receive: AM_MANYCAST drop: duplicate\n")); sys_declined++; @@ -1858,7 +1901,9 @@ receive( * packet is a replay. This prevents the bad guys from replaying * the most recent packet, authenticated or not. */ - } else if (L_ISEQU(&peer->xmt, &p_xmt)) { + } else if ( ((FLAG_LOOPNONCE & peer->flags) && L_ISEQU(&peer->nonce, &p_xmt)) + || (!(FLAG_LOOPNONCE & peer->flags) && L_ISEQU(&peer->xmt, &p_xmt)) + ) { DPRINTF(2, ("receive: drop: Duplicate xmit\n")); peer->flash |= TEST1; /* duplicate */ peer->oldpkt++; @@ -1958,6 +2003,10 @@ receive( * We have earlier asserted that hisstratum cannot be 0. * If hisstratum is STRATUM_UNSPEC, it means he's not sync'd. */ + + /* XXX: FLAG_LOOPNONCE */ + DEBUG_INSIST(0 == (FLAG_LOOPNONCE & peer->flags)); + } else if (peer->flip == 0) { if (0) { } else if (L_ISZERO(&p_org)) { @@ -1967,6 +2016,7 @@ receive( msyslog(LOG_INFO, "receive: BUG 3361: Clearing peer->aorg "); L_CLR(&peer->aorg); + /* Clear peer->nonce, too? */ #endif /**/ switch (hismode) { @@ -2020,6 +2070,7 @@ receive( } } else { L_CLR(&peer->aorg); + /* XXX: FLAG_LOOPNONCE */ } /* @@ -2193,7 +2244,7 @@ receive( peer->minpoll = peer->ppoll; peer->burst = peer->retry = 0; peer->throttle = (NTP_SHIFT + 1) * (1 << peer->minpoll); - poll_update(peer, pkt->ppoll); + poll_update(peer, pkt->ppoll, 0); return; /* kiss-o'-death */ } if (kissCode != NOKISS) { @@ -2383,9 +2434,17 @@ receive( /* * 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. + * more flashers. Leave if the packet is not good. */ process_packet(peer, pkt, rbufp->recv_length); + if (peer->flash & PKT_TEST_MASK) + return; + + /* [bug 3592] Update poll. Ideally this should not happen in a + * receive branch, but too much is going on here... at least we + * do it only if the packet was good! + */ + poll_update(peer, peer->hpoll, (peer->hmode == MODE_CLIENT)); /* * In interleaved mode update the state variables. Also adjust the @@ -2465,7 +2524,10 @@ process_packet( peer->seldisptoolarge++; DPRINTF(1, ("packet: flash header %04x\n", peer->flash)); - poll_update(peer, peer->hpoll); /* ppoll updated? */ + + /* ppoll updated? */ + /* XXX: Fuzz the poll? */ + poll_update(peer, peer->hpoll, (peer->hmode == MODE_CLIENT)); return; } @@ -2509,7 +2571,7 @@ process_packet( if (peer->burst > 0) peer->nextdate = current_time; } - poll_update(peer, peer->hpoll); + poll_update(peer, peer->hpoll, (peer->hmode == MODE_CLIENT)); /**/ @@ -2776,7 +2838,7 @@ clock_update( sys_poll = peer->minpoll; if (sys_poll > peer->maxpoll) sys_poll = peer->maxpoll; - poll_update(peer, sys_poll); + poll_update(peer, sys_poll, 0); sys_stratum = min(peer->stratum + 1, STRATUM_UNSPEC); if ( peer->stratum == STRATUM_REFCLOCK || peer->stratum == STRATUM_UNSPEC) @@ -2807,11 +2869,21 @@ clock_update( + clock_phi * (current_time - peer->update) + fabs(sys_offset); + p2_rootdisp = prev_rootdisp; + prev_rootdisp = sys_rootdisp; if (dtemp > sys_mindisp) sys_rootdisp = dtemp; else sys_rootdisp = sys_mindisp; + sys_rootdelay = peer->delay + peer->rootdelay; + + p2_reftime = prev_reftime; + p2_time = prev_time; + + prev_reftime = sys_reftime; + prev_time = current_time + 64 + (rand() & 0x3f); /* 64-127 s */ + sys_reftime = peer->dst; DPRINTF(1, ("clock_update: at %lu sample %lu associd %d\n", @@ -2856,7 +2928,11 @@ clock_update( sys_stratum = STRATUM_UNSPEC; memcpy(&sys_refid, "STEP", 4); sys_rootdelay = 0; + p2_rootdisp = 0; + prev_rootdisp = 0; sys_rootdisp = 0; + L_CLR(&p2_reftime); /* Should we clear p2_reftime? */ + L_CLR(&prev_reftime); /* Should we clear prev_reftime? */ L_CLR(&sys_reftime); sys_jitter = LOGTOD(sys_precision); leapsec_reset_frame(); @@ -2883,9 +2959,10 @@ clock_update( * first clock sync, send them home satisfied. */ #ifdef HAVE_WORKING_FORK - if (waitsync_fd_to_close != -1) { - close(waitsync_fd_to_close); - waitsync_fd_to_close = -1; + if (daemon_pipe[1] != -1) { + write(daemon_pipe[1], "S\n", 2); + close(daemon_pipe[1]); + daemon_pipe[1] = -1; DPRINTF(1, ("notified parent --wait-sync is done\n")); } #endif /* HAVE_WORKING_FORK */ @@ -2930,10 +3007,11 @@ clock_update( void poll_update( struct peer *peer, /* peer structure pointer */ - u_char mpoll + u_char mpoll, + u_char skewpoll ) { - u_long next, utemp; + u_long next, utemp, limit; u_char hpoll; /* @@ -2977,6 +3055,15 @@ poll_update( */ utemp = current_time + max(peer->throttle - (NTP_SHIFT - 1) * (1 << peer->minpoll), ntp_minpkt); + + /*[Bug 3592] avoid unlimited postpone of next poll */ + limit = (2u << hpoll); + if (limit > 64) + limit -= (limit >> 2); + limit += peer->outdate; + if (limit < current_time) + limit = current_time; + if (peer->burst > 0) { if (peer->nextdate > current_time) return; @@ -3022,6 +3109,29 @@ poll_update( next = ((0x1000UL | (ntp_random() & 0x0ff)) << hpoll) >> 12; next += peer->outdate; + /* XXX: bug3596: Deal with poll skew list? */ + if (skewpoll) { + psl_item psi; + + if (0 == get_pollskew(hpoll, &psi)) { + int sub = psi.sub; + int qty = psi.qty; + int msk = psi.msk; + int val; + + if ( 0 != sub + || 0 != qty) { + do { + val = ntp_random() & msk; + } while (val > qty); + + next -= sub; + next += val; + } + } else { + /* get_pollskew() already logged this */ + } + } if (next > utemp) peer->nextdate = next; else @@ -3029,6 +3139,13 @@ poll_update( if (peer->throttle > (1 << peer->minpoll)) peer->nextdate += ntp_minpkt; } + + /*[Bug 3592] avoid unlimited postpone of next poll */ + if (peer->nextdate > limit) { + DPRINTF(1, ("poll_update: clamp reached; limit %lu next %lu\n", + limit, peer->nextdate)); + peer->nextdate = limit; + } DPRINTF(2, ("poll_update: at %lu %s poll %d burst %d retry %d head %d early %lu next %lu\n", current_time, ntoa(&peer->srcadr), peer->hpoll, peer->burst, peer->retry, peer->throttle, @@ -3953,6 +4070,7 @@ peer_xmit( xpkt.refid = sys_refid; xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay)); xpkt.rootdisp = HTONS_FP(DTOUFP(sys_rootdisp)); + /* Use sys_reftime for peer exchanges */ HTONL_FP(&sys_reftime, &xpkt.reftime); HTONL_FP(&peer->rec, &xpkt.org); HTONL_FP(&peer->dst, &xpkt.rec); @@ -4377,7 +4495,7 @@ leap_smear_add_offs( static void fast_xmit( struct recvbuf *rbufp, /* receive packet pointer */ - int xmode, /* receive mode */ + int xmode, /* receive mode */ /* XXX: HMS: really? */ keyid_t xkeyid, /* transmit key ID */ int flags /* restrict mask */ ) @@ -4408,8 +4526,8 @@ fast_xmit( /* * If this is a kiss-o'-death (KoD) packet, show leap * unsynchronized, stratum zero, reference ID the four-character - * kiss code and system root delay. Note we don't reveal the - * local time, so these packets can't be used for + * kiss code and (???) system root delay. Note we don't reveal + * the local time, so these packets can't be used for * synchronization. */ if (flags & RES_KOD) { @@ -4431,18 +4549,23 @@ fast_xmit( * This is a normal packet. Use the system variables. */ } else { + double this_rootdisp; + l_fp this_ref_time; + #ifdef LEAP_SMEAR /* * Make copies of the variables which can be affected by smearing. */ - l_fp this_ref_time; l_fp this_recv_time; #endif /* - * If we are inside the leap smear interval we add the current smear offset to - * the packet receive time, to the packet transmit time, and eventually to the - * reftime to make sure the reftime isn't later than the transmit/receive times. + * If we are inside the leap smear interval we add + * the current smear offset to: + * - the packet receive time, + * - the packet transmit time, + * - and eventually to the reftime to make sure the + * reftime isn't later than the transmit/receive times. */ xpkt.li_vn_mode = PKT_LI_VN_MODE(xmt_leap, PKT_VERSION(rpkt->li_vn_mode), xmode); @@ -4452,25 +4575,77 @@ fast_xmit( xpkt.precision = sys_precision; xpkt.refid = sys_refid; xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay)); - xpkt.rootdisp = HTONS_FP(DTOUFP(sys_rootdisp)); + + /* + ** Server Response Fuzzing + ** + ** Which values do we want to use for reftime and rootdisp? + */ + + if ( MODE_SERVER == xmode + && RES_SRVRSPFUZ & flags) { + if (current_time < p2_time) { + this_ref_time = p2_reftime; + this_rootdisp = p2_rootdisp; + } else if (current_time < prev_time) { + this_ref_time = prev_reftime; + this_rootdisp = prev_rootdisp; + } else { + this_ref_time = sys_reftime; + this_rootdisp = sys_rootdisp; + } + + SRVRSP_FUZZ(this_ref_time); + } else { + this_ref_time = sys_reftime; + this_rootdisp = sys_rootdisp; + } + + /* + ** ROOT DISPERSION + */ + + xpkt.rootdisp = HTONS_FP(DTOUFP(this_rootdisp)); + + /* + ** REFTIME + */ #ifdef LEAP_SMEAR - this_ref_time = sys_reftime; if (leap_smear.in_progress) { + /* adjust the reftime by the same amount as the + * leap smear, as we don't want to risk the + * reftime being later than the transmit time. + */ leap_smear_add_offs(&this_ref_time, NULL); + } +#endif + + HTONL_FP(&this_ref_time, &xpkt.reftime); + + /* + ** REFID + */ + +#ifdef LEAP_SMEAR + if (leap_smear.in_progress) { xpkt.refid = convertLFPToRefID(leap_smear.offset); DPRINTF(2, ("fast_xmit: leap_smear.in_progress: refid %8x, smear %s\n", ntohl(xpkt.refid), lfptoa(&leap_smear.offset, 8) )); } - HTONL_FP(&this_ref_time, &xpkt.reftime); -#else - HTONL_FP(&sys_reftime, &xpkt.reftime); #endif + /* + ** ORIGIN + */ + xpkt.org = rpkt->xmt; + /* + ** RECEIVE + */ #ifdef LEAP_SMEAR this_recv_time = rbufp->recv_time; if (leap_smear.in_progress) @@ -4480,6 +4655,10 @@ fast_xmit( HTONL_FP(&rbufp->recv_time, &xpkt.rec); #endif + /* + ** TRANSMIT + */ + get_systime(&xmt_tx); #ifdef LEAP_SMEAR if (leap_smear.in_progress) @@ -4580,10 +4759,11 @@ pool_xmit( struct interface * lcladr; sockaddr_u * rmtadr; r4addr r4a; - int restrict_mask; + u_short restrict_mask; struct peer * p; l_fp xmt_tx; + DEBUG_REQUIRE(pool); if (NULL == pool->ai) { if (pool->addrs != NULL) { /* free() is used with copy_addrinfo_list() */ @@ -4635,10 +4815,28 @@ pool_xmit( xpkt.refid = sys_refid; xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay)); xpkt.rootdisp = HTONS_FP(DTOUFP(sys_rootdisp)); + /* Bug 3596: What are the pros/cons of using sys_reftime here? */ HTONL_FP(&sys_reftime, &xpkt.reftime); + + /* HMS: the following is better done after the ntp_random() calls */ get_systime(&xmt_tx); pool->aorg = xmt_tx; - HTONL_FP(&xmt_tx, &xpkt.xmt); + + if (FLAG_LOOPNONCE & pool->flags) { + l_fp nonce; + + do { + nonce.l_ui = ntp_random(); + } while (0 == nonce.l_ui); + do { + nonce.l_uf = ntp_random(); + } while (0 == nonce.l_uf); + pool->nonce = nonce; + HTONL_FP(&nonce, &xpkt.xmt); + } else { + L_CLR(&pool->nonce); + HTONL_FP(&xmt_tx, &xpkt.xmt); + } sendpkt(rmtadr, lcladr, sys_ttl[(pool->ttl >= sys_ttlmax) ? sys_ttlmax : pool->ttl], &xpkt, LEN_PKT_NOMAC); |
