aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/ntp/ntpd/ntp_proto.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ntp/ntpd/ntp_proto.c')
-rw-r--r--contrib/ntp/ntpd/ntp_proto.c151
1 files changed, 122 insertions, 29 deletions
diff --git a/contrib/ntp/ntpd/ntp_proto.c b/contrib/ntp/ntpd/ntp_proto.c
index 513b99f683e3..ad04ed4ac0d7 100644
--- a/contrib/ntp/ntpd/ntp_proto.c
+++ b/contrib/ntp/ntpd/ntp_proto.c
@@ -138,6 +138,7 @@ char *sys_ident = NULL; /* identity scheme */
* TOS and multicast mapping stuff
*/
int sys_floor = 0; /* cluster stratum floor */
+u_char sys_bcpollbstep = 0; /* Broadcast Poll backstep gate */
int sys_ceiling = STRATUM_UNSPEC - 1; /* cluster stratum ceiling */
int sys_minsane = 1; /* minimum candidates */
int sys_minclock = NTP_MINCLOCK; /* minimum candidates */
@@ -278,7 +279,7 @@ valid_NAK(
u_char hismode
)
{
- int base_packet_length = MIN_V4_PKT_LEN;
+ int base_packet_length = MIN_V4_PKT_LEN;
int remainder_size;
struct pkt * rpkt;
int keyid;
@@ -335,7 +336,7 @@ valid_NAK(
myorg = &peer->borg;
else
myorg = &peer->aorg;
-
+
if (L_ISZERO(&p_org) ||
L_ISZERO( myorg) ||
!L_ISEQU(&p_org, myorg)) {
@@ -1450,22 +1451,66 @@ receive(
++bail;
}
- /* too early? worth an error, too! */
+ /* too early? worth an error, too!
+ *
+ * [Bug 3113] Ensure that at least one poll
+ * interval has elapsed since the last **clean**
+ * packet was received. We limit the check to
+ * **clean** packets to prevent replayed packets
+ * and incorrectly authenticated packets, which
+ * we'll discard, from being used to create a
+ * denial of service condition.
+ */
deadband = (1u << pkt->ppoll);
if (FLAG_BC_VOL & peer->flags)
deadband -= 3; /* allow greater fuzz after volley */
- if ((current_time - peer->timelastrec) < deadband) {
+ if ((current_time - peer->timereceived) < deadband) {
msyslog(LOG_INFO, "receive: broadcast packet from %s arrived after %lu, not %lu seconds!",
stoa(&rbufp->recv_srcadr),
- (current_time - peer->timelastrec),
+ (current_time - peer->timereceived),
deadband);
++bail;
}
- /* Alert if time from the server is non-monotonic */
- tdiff = p_xmt;
- L_SUB(&tdiff, &peer->bxmt);
- if (tdiff.l_i < 0) {
+ /* Alert if time from the server is non-monotonic.
+ *
+ * [Bug 3114] is about Broadcast mode replay DoS.
+ *
+ * Broadcast mode *assumes* a trusted network.
+ * Even so, it's nice to be robust in the face
+ * of attacks.
+ *
+ * If we get an authenticated broadcast packet
+ * with an "earlier" timestamp, it means one of
+ * two things:
+ *
+ * - the broadcast server had a backward step.
+ *
+ * - somebody is trying a replay attack.
+ *
+ * deadband: By default, we assume the broadcast
+ * network is trustable, so we take our accepted
+ * broadcast packets as we receive them. But
+ * some folks might want to take additional poll
+ * delays before believing a backward step.
+ */
+ if (sys_bcpollbstep) {
+ /* pkt->ppoll or peer->ppoll ? */
+ deadband = (1u << pkt->ppoll)
+ * sys_bcpollbstep + 2;
+ } else {
+ deadband = 0;
+ }
+
+ if (L_ISZERO(&peer->bxmt)) {
+ tdiff.l_ui = tdiff.l_uf = 0;
+ } else {
+ tdiff = p_xmt;
+ L_SUB(&tdiff, &peer->bxmt);
+ }
+ if (tdiff.l_i < 0 &&
+ (current_time - peer->timereceived) < deadband)
+ {
msyslog(LOG_INFO, "receive: broadcast packet from %s contains non-monotonic timestamp: %#010x.%08x -> %#010x.%08x",
stoa(&rbufp->recv_srcadr),
peer->bxmt.l_ui, peer->bxmt.l_uf,
@@ -1474,8 +1519,6 @@ receive(
++bail;
}
- peer->bxmt = p_xmt;
-
if (bail) {
peer->timelastrec = current_time;
sys_declined++;
@@ -1623,7 +1666,7 @@ receive(
peer->borg.l_ui, peer->borg.l_uf);
return;
}
-
+
/*
* Basic mode checks:
*
@@ -1645,13 +1688,38 @@ receive(
} else if (peer->flip == 0) {
INSIST(0 != hisstratum);
INSIST(STRATUM_UNSPEC != hisstratum);
+
if (0) {
} else if (L_ISZERO(&p_org)) {
+ char *action;
+
+ L_CLR(&peer->aorg);
+ /**/
+ switch (hismode) {
+ /* We allow 0org for: */
+ case UCHAR_MAX:
+ action = "Allow";
+ break;
+ /* We disallow 0org for: */
+ case MODE_UNSPEC:
+ case MODE_ACTIVE:
+ case MODE_PASSIVE:
+ case MODE_CLIENT:
+ case MODE_SERVER:
+ case MODE_BROADCAST:
+ action = "Drop";
+ peer->bogusorg++;
+ peer->flash |= TEST2; /* bogus */
+ break;
+ default:
+ INSIST(!"receive(): impossible hismode");
+ break;
+ }
+ /**/
msyslog(LOG_INFO,
- "receive: Got 0 origin timestamp from %s@%s xmt %#010x.%08x",
- hm_str, ntoa(&peer->srcadr),
+ "receive: %s 0 origin timestamp from %s@%s xmt %#010x.%08x",
+ action, hm_str, ntoa(&peer->srcadr),
ntohl(pkt->xmt.l_ui), ntohl(pkt->xmt.l_uf));
- L_CLR(&peer->aorg);
} else if (!L_ISEQU(&p_org, &peer->aorg)) {
/* are there cases here where we should bail? */
/* Should we set TEST2 if we decide to try xleave? */
@@ -1800,6 +1868,12 @@ receive(
"receive: Bad broadcast auth (%d) from %s",
is_authentic, ntoa(&peer->srcadr));
}
+
+ /*
+ * Now that we know the packet is correctly authenticated,
+ * update peer->bxmt.
+ */
+ peer->bxmt = p_xmt;
}
@@ -1878,7 +1952,7 @@ receive(
peer->badauth++;
return;
}
- break;
+ break;
case MODE_CLIENT: /* client mode */
#if 0 /* At this point, MODE_CONTROL is overloaded by MODE_BCLIENT */
@@ -1886,14 +1960,14 @@ receive(
#endif
case MODE_PRIVATE: /* private mode */
case MODE_BCLIENT: /* broadcast client mode */
- break;
+ break;
case MODE_UNSPEC: /* unspecified (old version) */
default:
msyslog(LOG_INFO,
"receive: Unexpected mode (%d) in packet from %s",
hismode, ntoa(&peer->srcadr));
- break;
+ break;
}
@@ -2695,6 +2769,7 @@ peer_clear(
)
{
u_char u;
+ l_fp bxmt = peer->bxmt; /* bcast clients retain this! */
#ifdef AUTOKEY
/*
@@ -2731,6 +2806,10 @@ peer_clear(
peer->flash = peer_unfit(peer);
peer->jitter = LOGTOD(sys_precision);
+ /* Don't throw away our broadcast replay protection */
+ if (peer->hmode == MODE_BCLIENT)
+ peer->bxmt = bxmt;
+
/*
* If interleave mode, initialize the alternate origin switch.
*/
@@ -3040,8 +3119,9 @@ clock_select(void)
* Leave the island immediately if the peer is
* unfit to synchronize.
*/
- if (peer_unfit(peer))
+ if (peer_unfit(peer)) {
continue;
+ }
/*
* If this peer is an orphan parent, elect the
@@ -3081,8 +3161,9 @@ clock_select(void)
* parent in ancestry so are excluded.
* See http://bugs.ntp.org/2050
*/
- if (peer->stratum > sys_orphan)
+ if (peer->stratum > sys_orphan) {
continue;
+ }
#ifdef REFCLOCK
/*
* The following are special cases. We deal
@@ -3531,15 +3612,15 @@ root_distance(
/*
* Root Distance (LAMBDA) is defined as:
- * (delta + DELTA)/2 + epsilon + EPSILON + phi
+ * (delta + DELTA)/2 + epsilon + EPSILON + D
*
* where:
* delta is the round-trip delay
* DELTA is the root delay
- * epsilon is the remote server precision + local precision
+ * epsilon is the peer dispersion
* + (15 usec each second)
* EPSILON is the root dispersion
- * phi is the peer jitter statistic
+ * D is sys_jitter
*
* NB: Think hard about why we are using these values, and what
* the alternatives are, and the various pros/cons.
@@ -3548,8 +3629,7 @@ root_distance(
* other worse choices.
*/
dtemp = (peer->delay + peer->rootdelay) / 2
- + LOGTOD(peer->precision)
- + LOGTOD(sys_precision)
+ + peer->disp
+ clock_phi * (current_time - peer->update)
+ peer->rootdisp
+ peer->jitter;
@@ -3995,6 +4075,10 @@ leap_smear_add_offs(
L_ADD(t, &leap_smear.offset);
+ /*
+ ** XXX: Should the smear be added to the root dispersion?
+ */
+
return;
}
@@ -4425,8 +4509,9 @@ peer_unfit(
*/
if ( peer->leap == LEAP_NOTINSYNC
|| peer->stratum < sys_floor
- || peer->stratum >= sys_ceiling)
+ || peer->stratum >= sys_ceiling) {
rval |= TEST10; /* bad synch or stratum */
+ }
/*
* A distance error for a remote peer occurs if the root
@@ -4435,8 +4520,9 @@ peer_unfit(
*/
if ( !(peer->flags & FLAG_REFCLOCK)
&& root_distance(peer) >= sys_maxdist
- + clock_phi * ULOGTOD(peer->hpoll))
+ + clock_phi * ULOGTOD(peer->hpoll)) {
rval |= TEST11; /* distance exceeded */
+ }
/*
* A loop error occurs if the remote peer is synchronized to the
@@ -4444,15 +4530,17 @@ peer_unfit(
* server as the local peer but only if the remote peer is
* neither a reference clock nor an orphan.
*/
- if (peer->stratum > 1 && local_refid(peer))
+ if (peer->stratum > 1 && local_refid(peer)) {
rval |= TEST12; /* synchronization loop */
+ }
/*
* An unreachable error occurs if the server is unreachable or
* the noselect bit is set.
*/
- if (!peer->reach || (peer->flags & FLAG_NOSELECT))
+ if (!peer->reach || (peer->flags & FLAG_NOSELECT)) {
rval |= TEST13; /* unreachable */
+ }
peer->flash &= ~PEER_TEST_MASK;
peer->flash |= rval;
@@ -4717,6 +4805,11 @@ proto_config(
/*
* tos command - arguments are double, sometimes cast to int
*/
+
+ case PROTO_BCPOLLBSTEP: /* Broadcast Poll Backstep gate (bcpollbstep) */
+ sys_bcpollbstep = (u_char)dvalue;
+ break;
+
case PROTO_BEACON: /* manycast beacon (beacon) */
sys_beacon = (int)dvalue;
break;