aboutsummaryrefslogtreecommitdiff
path: root/ntpd/ntp_proto.c
diff options
context:
space:
mode:
Diffstat (limited to 'ntpd/ntp_proto.c')
-rw-r--r--ntpd/ntp_proto.c306
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);