#include "ntp_io.h"
#include "ntp_refclock.h"
#include "ntp_control.h"
+#include "ntp_unixtime.h"
#include "ntp_stdlib.h"
#include <stdio.h>
static void ctl_putarray P((const char *, double *, int));
static void ctl_putsys P((int));
static void ctl_putpeer P((int, struct peer *));
+static void ctl_putfs P((const char *, tstamp_t));
#ifdef REFCLOCK
static void ctl_putclock P((int, struct refclockstat *, int));
#endif /* REFCLOCK */
{ CS_HOST, RO, "hostname" }, /* 22 */
{ CS_PUBLIC, RO, "hostkey" }, /* 23 */
{ CS_CERTIF, RO, "cert" }, /* 24 */
- { CS_REVTIME, RO, "refresh" }, /* 25 */
+ { CS_REVTIME, RO, "expire" }, /* 25 */
{ CS_LEAPTAB, RO, "leapsec" }, /* 26 */
{ CS_TAI, RO, "tai" }, /* 27 */
{ CS_DIGEST, RO, "signature" }, /* 28 */
{ CS_IDENT, RO, "ident" }, /* 29 */
+ { CS_REVOKE, RO, "expire" }, /* 30 */
#endif /* OPENSSL */
- { 0, EOV, "" } /* 21/30 */
+ { 0, EOV, "" } /* 21/31 */
};
static struct ctl_var *ext_sys_var = (struct ctl_var *)0;
CS_DIGEST,
CS_FLAGS,
CS_PUBLIC,
- CS_REVTIME,
CS_IDENT,
CS_LEAPTAB,
CS_TAI,
ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
}
+/*
+ * ctl_putfs - write a decoded filestamp into the response
+ */
+static void
+ctl_putfs(
+ const char *tag,
+ tstamp_t uval
+ )
+{
+ register char *cp;
+ register const char *cq;
+ char buffer[200];
+ struct tm *tm = NULL;
+ time_t fstamp;
+
+ cp = buffer;
+ cq = tag;
+ while (*cq != '\0')
+ *cp++ = *cq++;
+
+ *cp++ = '=';
+ fstamp = uval - JAN_1970;
+ tm = gmtime(&fstamp);
+ if (tm == NULL)
+ return;
+
+ sprintf(cp, "%04d%02d%02d%04d", tm->tm_year + 1900, tm->tm_mon,
+ tm->tm_mday + 1, tm->tm_hour * 60 + tm->tm_min);
+ while (*cp != '\0')
+ cp++;
+ ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
+}
+
/*
* ctl_puthex - write a tagged unsigned integer, in hex, into the response
case CS_CERTIF:
for (cp = cinfo; cp != NULL; cp = cp->link) {
- sprintf(cbuf, "%s %s 0x%x %u", cp->subject,
- cp->issuer, cp->flags,
- ntohl(cp->cert.fstamp));
+ sprintf(cbuf, "%s %s 0x%x", cp->subject,
+ cp->issuer, cp->flags);
ctl_putstr(sys_var[CS_CERTIF].text, cbuf,
strlen(cbuf));
+ ctl_putfs(sys_var[CS_REVOKE].text, cp->last);
}
break;
case CS_PUBLIC:
if (hostval.fstamp != 0)
- ctl_putuint(sys_var[CS_PUBLIC].text,
+ ctl_putfs(sys_var[CS_PUBLIC].text,
ntohl(hostval.fstamp));
break;
case CS_REVTIME:
if (hostval.tstamp != 0)
- ctl_putuint(sys_var[CS_REVTIME].text,
+ ctl_putfs(sys_var[CS_REVTIME].text,
ntohl(hostval.tstamp));
break;
case CS_LEAPTAB:
if (tai_leap.fstamp != 0)
- ctl_putuint(sys_var[CS_LEAPTAB].text,
+ ctl_putfs(sys_var[CS_LEAPTAB].text,
ntohl(tai_leap.fstamp));
break;
case CP_HOST:
if (peer->subject != NULL)
- ctl_putstr(peer_var[CP_HOST].text, peer->subject,
- strlen(peer->subject));
+ ctl_putstr(peer_var[CP_HOST].text,
+ peer->subject, strlen(peer->subject));
break;
- case CP_VALID:
- if (peer->pkey == NULL)
- break;
-
- sprintf(str, "%u:%u", peer->first, peer->last);
- ctl_putstr(peer_var[CP_VALID].text, str, strlen(str));
+ case CP_VALID: /* not used */
break;
case CP_IDENT:
if (peer->issuer != NULL)
- ctl_putstr(peer_var[CP_IDENT].text, peer->issuer,
- strlen(peer->issuer));
+ ctl_putstr(peer_var[CP_IDENT].text,
+ peer->issuer, strlen(peer->issuer));
break;
case CP_INITSEQ:
break;
ctl_putint(peer_var[CP_INITSEQ].text, ap->seq);
ctl_puthex(peer_var[CP_INITKEY].text, ap->key);
- ctl_putuint(peer_var[CP_INITTSP].text,
+ ctl_putfs(peer_var[CP_INITTSP].text,
ntohl(peer->recval.tstamp));
break;
#endif /* OPENSSL */
keyid_t keyid = 0; /* next key ID */
keyid_t cookie; /* private value */
u_long lifetime;
- u_int len;
+ u_int len, mpoll;
int i;
/*
* included in the hash is zero if broadcast mode, the peer
* cookie if client mode or the host cookie if symmetric modes.
*/
- lifetime = min(sys_automax, NTP_MAXSESSION * (1 <<
- peer->hpoll));
+ mpoll = 1 << min(peer->ppoll, peer->hpoll);
+ lifetime = min(sys_automax, NTP_MAXSESSION * mpoll);
if (peer->hmode == MODE_BROADCAST)
cookie = 0;
else
peer->keynumber = i;
keyid = session_key(&dstadr->sin, &peer->srcadr, keyid,
cookie, lifetime);
- lifetime -= 1 << peer->hpoll;
+ lifetime -= mpoll;
if (auth_havekey(keyid) || keyid <= NTP_MAXKEY ||
- lifetime <= (1 << peer->hpoll))
+ lifetime <= mpoll)
break;
}
X509 *cert; /* X509 certificate */
char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
keyid_t cookie; /* crumbles */
+ int hismode; /* packet mode */
int rval = XEVNT_OK;
u_char *ptr;
u_int32 temp32;
* association ID is saved only if nonzero.
*/
authlen = LEN_PKT_NOMAC;
+ hismode = (int)PKT_MODE((&rbufp->recv_pkt)->li_vn_mode);
while ((has_mac = rbufp->recv_length - authlen) > MAX_MAC_LEN) {
pkt = (u_int32 *)&rbufp->recv_pkt + authlen / 4;
ep = (struct exten *)pkt;
* defines the signature scheme. Note the request and
* response are identical, but neither is validated by
* signature. The request is processed here only in
- * symmetric modes. The server name field would be
+ * symmetric modes. The server name field might be
* useful to implement access controls in future.
*/
case CRYPTO_ASSOC:
/*
- * Pass the extension field to the transmit
- * side.
+ * Discard the message if it has already been
+ * stored. Otherwise, pass the extension field
+ * to the transmit side.
*/
+ if (peer->crypto)
+ break;
+
fp = emalloc(len);
memcpy(fp, ep, len);
temp32 = CRYPTO_RESP;
/*
* Discard the message if it has already been
- * stored or the server is not synchronized.
+ * stored or the message has been amputated.
*/
- if (peer->crypto || !fstamp)
+ if (peer->crypto)
break;
- if (len < VALUE_LEN + vallen) {
+ if (vallen == 0 || vallen > MAXHOSTNAME ||
+ len < VALUE_LEN + vallen) {
rval = XEVNT_LEN;
break;
}
* identity are presumed valid, so we skip the
* certificate and identity exchanges and move
* immediately to the cookie exchange which
- * confirms the server signature. If the client
- * has IFF or GC or both, the server must have
- * the same one or both. Otherwise, the default
- * TC scheme is used.
+ * confirms the server signature.
*/
+ temp32 = crypto_flags & fstamp &
+ CRYPTO_FLAG_MASK;
if (crypto_flags & CRYPTO_FLAG_PRIV) {
- if (!(fstamp & CRYPTO_FLAG_PRIV))
+ if (!(fstamp & CRYPTO_FLAG_PRIV)) {
rval = XEVNT_KEY;
- else
+ break;
+
+ } else {
fstamp |= CRYPTO_FLAG_VALID |
- CRYPTO_FLAG_VRFY;
- } else if (crypto_flags & CRYPTO_FLAG_MASK &&
- !(crypto_flags & fstamp & CRYPTO_FLAG_MASK))
- {
+ CRYPTO_FLAG_VRFY |
+ CRYPTO_FLAG_SIGN;
+ }
+ /*
+ * In symmetric modes it is an error if either
+ * peer requests identity and the other peer
+ * does not support it.
+ */
+ } else if ((hismode == MODE_ACTIVE || hismode ==
+ MODE_PASSIVE) && ((crypto_flags | fstamp) &
+ CRYPTO_FLAG_MASK) && !temp32) {
rval = XEVNT_KEY;
- } else {
- fstamp &= ~CRYPTO_FLAG_MASK;
+ break;
+ /*
+ * It is an error if the client requests
+ * identity and the server does not support it.
+ */
+ } else if (hismode == MODE_CLIENT && (fstamp &
+ CRYPTO_FLAG_MASK) && !temp32) {
+ rval = XEVNT_KEY;
+ break;
}
/*
- * Discard the message if identity error.
+ * Otherwise, the identity scheme(s) are those
+ * that both client and server support.
*/
- if (rval != XEVNT_OK)
- break;
+ fstamp = temp32 | (fstamp & ~CRYPTO_FLAG_MASK);
/*
- * Discard the message if the host name length
- * is unreasonable or the signature digest NID
- * is not supported.
+ * Discard the message if the signature digest
+ * NID is not supported.
*/
temp32 = (fstamp >> 16) & 0xffff;
dp =
(const EVP_MD *)EVP_get_digestbynid(temp32);
- if (vallen == 0 || vallen > MAXHOSTNAME)
- rval = XEVNT_LEN;
- else if (dp == NULL)
+ if (dp == NULL) {
rval = XEVNT_MD;
- if (rval != XEVNT_OK)
break;
+ }
/*
* Save status word, host name and message
- * digest/signature type. If PC identity, be
- * sure not to sign the certificate.
+ * digest/signature type.
*/
- if (crypto_flags & CRYPTO_FLAG_PRIV)
- fstamp |= CRYPTO_FLAG_SIGN;
peer->crypto = fstamp;
peer->digest = dp;
peer->subject = emalloc(vallen + 1);
case CRYPTO_CERT | CRYPTO_RESP:
/*
- * Discard the message if invalid or identity
- * already confirmed.
+ * Discard the message if invalid.
*/
- if (peer->crypto & CRYPTO_FLAG_VRFY)
- break;
-
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
case CRYPTO_IFF | CRYPTO_RESP:
/*
- * Discard the message if invalid or identity
- * already confirmed.
+ * Discard the message if invalid or certificate
+ * trail not trusted.
*/
- if (peer->crypto & CRYPTO_FLAG_VRFY)
+ if (!(peer->crypto & CRYPTO_FLAG_VALID)) {
+ rval = XEVNT_ERR;
break;
-
+ }
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
case CRYPTO_GQ | CRYPTO_RESP:
/*
- * Discard the message if invalid or identity
- * already confirmed.
+ * Discard the message if invalid or certificate
+ * trail not trusted.
*/
- if (peer->crypto & CRYPTO_FLAG_VRFY)
+ if (!(peer->crypto & CRYPTO_FLAG_VALID)) {
+ rval = XEVNT_ERR;
break;
-
+ }
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
case CRYPTO_MV | CRYPTO_RESP:
/*
- * Discard the message if invalid or identity
- * already confirmed.
+ * Discard the message if invalid or certificate
+ * trail not trusted.
*/
- if (peer->crypto & CRYPTO_FLAG_VRFY)
+ if (!(peer->crypto & CRYPTO_FLAG_VALID)) {
+ rval = XEVNT_ERR;
break;
-
+ }
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
case CRYPTO_SIGN | CRYPTO_RESP:
/*
- * Discard the message if invalid or identity
- * not confirmed.
+ * Discard the message if invalid or not
+ * proventic.
*/
- if (!(peer->crypto & CRYPTO_FLAG_VRFY))
+ if (!(peer->crypto & CRYPTO_FLAG_PROV)) {
+ rval = XEVNT_ERR;
break;
-
+ }
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
case CRYPTO_COOK:
/*
- * Discard the message if invalid or identity
- * not confirmed.
+ * Discard the message if invalid.
*/
- if (!(peer->crypto & CRYPTO_FLAG_VRFY))
- break;
-
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
* not confirmed or signature not verified with
* respect to the cookie values.
*/
- if (!(peer->crypto & CRYPTO_FLAG_VRFY))
+ if (!(peer->crypto & CRYPTO_FLAG_VRFY)) {
+ rval = XEVNT_ERR;
break;
-
+ }
if ((rval = crypto_verify(ep, &peer->cookval,
peer)) != XEVNT_OK)
break;
* not confirmed or signature not verified with
* respect to the receive autokey values.
*/
- if (!(peer->crypto & CRYPTO_FLAG_VRFY))
+ if (!(peer->crypto & CRYPTO_FLAG_VRFY)) {
+ rval = XEVNT_ERR;
break;
-
+ }
if ((rval = crypto_verify(ep, &peer->recval,
peer)) != XEVNT_OK)
break;
case CRYPTO_TAI:
/*
- * Discard the message if invalid or identity
- * not confirmed.
+ * Discard the message if invalid.
*/
- if (!(peer->crypto & CRYPTO_FLAG_VRFY))
- break;
-
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
case CRYPTO_TAI | CRYPTO_RESP:
/*
- * Discard the message if invalid or identity
- * not confirmed or signature not verified with
+ * Discard the message if invalid or not
+ * proventic or signature not verified with
* respect to the leapsecond table values.
*/
- if (!(peer->crypto & CRYPTO_FLAG_VRFY))
- break;
-
- if ((rval = crypto_verify(ep, &peer->tai_leap,
- peer)) != XEVNT_OK)
+ if (!(peer->crypto & CRYPTO_FLAG_VRFY)) {
+ rval = XEVNT_ERR;
break;
+ }
+ if (peer->cmmd == NULL) {
+ if ((rval = crypto_verify(ep,
+ &peer->tai_leap, peer)) != XEVNT_OK)
+ break;
+ }
/*
* Initialize peer variables, leapseconds
opcode |= CRYPTO_ERROR;
break;
}
- if ((rval = crypto_alice(peer, &vtemp)) == XEVNT_OK)
+ if ((rval = crypto_alice(peer, &vtemp)) == XEVNT_OK) {
len += crypto_send(fp, &vtemp);
- value_free(&vtemp);
+ value_free(&vtemp);
+ }
break;
/*
* Send response in Schnorr (IFF) identity scheme.
*/
case CRYPTO_IFF | CRYPTO_RESP:
- if ((rval = crypto_bob(ep, &vtemp)) == XEVNT_OK)
+ if ((rval = crypto_bob(ep, &vtemp)) == XEVNT_OK) {
len += crypto_send(fp, &vtemp);
- value_free(&vtemp);
+ value_free(&vtemp);
+ }
break;
/*
opcode |= CRYPTO_ERROR;
break;
}
- if ((rval = crypto_alice2(peer, &vtemp)) == XEVNT_OK)
+ if ((rval = crypto_alice2(peer, &vtemp)) == XEVNT_OK) {
len += crypto_send(fp, &vtemp);
- value_free(&vtemp);
+ value_free(&vtemp);
+ }
break;
/*
* Send response in Guillou-Quisquater (GQ) identity scheme.
*/
case CRYPTO_GQ | CRYPTO_RESP:
- if ((rval = crypto_bob2(ep, &vtemp)) == XEVNT_OK)
+ if ((rval = crypto_bob2(ep, &vtemp)) == XEVNT_OK) {
len += crypto_send(fp, &vtemp);
- value_free(&vtemp);
+ value_free(&vtemp);
+ }
break;
/*
opcode |= CRYPTO_ERROR;
break;
}
- if ((rval = crypto_alice3(peer, &vtemp)) == XEVNT_OK)
+ if ((rval = crypto_alice3(peer, &vtemp)) == XEVNT_OK) {
len += crypto_send(fp, &vtemp);
- value_free(&vtemp);
+ value_free(&vtemp);
+ }
break;
/*
* Send response in MV identity scheme.
*/
case CRYPTO_MV | CRYPTO_RESP:
- if ((rval = crypto_bob3(ep, &vtemp)) == XEVNT_OK)
+ if ((rval = crypto_bob3(ep, &vtemp)) == XEVNT_OK) {
len += crypto_send(fp, &vtemp);
- value_free(&vtemp);
+ value_free(&vtemp);
+ }
break;
/*
opcode |= CRYPTO_ERROR;
sprintf(statstr, "error %x opcode %x", rval, opcode);
record_crypto_stats(srcadr_sin, statstr);
+ report_event(rval, NULL);
#ifdef DEBUG
if (debug)
printf("crypto_xmit: %s\n", statstr);
* If the IFF parameters are not valid, something awful
* happened or we are being tormented.
*/
- if (!(crypto_flags & CRYPTO_FLAG_IFF)) {
+ if (iffpar_pkey == NULL) {
msyslog(LOG_INFO, "crypto_bob: scheme unavailable");
return (XEVNT_ID);
}
* If the GQ parameters are not valid, something awful
* happened or we are being tormented.
*/
- if (!(crypto_flags & CRYPTO_FLAG_GQ)) {
+ if (gqpar_pkey == NULL) {
msyslog(LOG_INFO, "crypto_bob2: scheme unavailable");
return (XEVNT_ID);
}
* If the MV parameters are not valid, something awful
* happened or we are being tormented.
*/
- if (!(crypto_flags & CRYPTO_FLAG_MV)) {
+ if (mvpar_pkey == NULL) {
msyslog(LOG_INFO, "crypto_bob3: scheme unavailable");
return (XEVNT_ID);
}
-/*
+y/*
* ntp_proto.c - NTP version 4 protocol machinery
*
* ATTENTION: Get approval from Dave Mills on all changes to this file!
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 */
*/
/*
* In broadcast mode the poll interval is never changed from
- * minpoll.
+ * minpoll. Orphan mode is active when enabled and when no other
+ * source is available. In this mode broadcasts are made at the
+ * orphan stratum and with root delay randomized over a 1-s
+ * range. The root delay is used by the election algorithm to
+ * select a single source from among the orphan dwellers.
*/
hpoll = peer->hpoll;
if (peer->cast_flags & (MDF_BCAST | MDF_MCAST)) {
peer->outdate = current_time;
- if (sys_peer != NULL)
+ if (sys_peer != NULL) {
+ peer_xmit(peer);
+ } else if (sys_orphan < STRATUM_UNSPEC) {
+ sys_leap = LEAP_NOWARNING;
+ sys_stratum = sys_orphan;
peer_xmit(peer);
+ }
poll_update(peer, hpoll);
return;
}
u_char oreach;
/*
- * Update the reachability status.
+ * Update the reachability status. If not heard for
+ * three consecutive polls, stuff infinity in the clock
+ * filter.
*/
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) {
/*
peer->unreach == 0) {
peer->burst = NTP_BURST;
}
+ if (!(peer->flags & FLAG_PREEMPT))
+ peer->unreach++;
+ else
+ peer->unreach += 3;
} else {
/*
- * Here the peer is reachable. If it has not
- * been heard for three consecutive polls, stuff
- * infinity in the clock filter. Next, set the
- * poll interval to the system poll interval.
- * Send a burst only if enabled and the peer is
- * fit.
+ * 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 (!(peer->reach & 0x07))
- clock_filter(peer, 0., 0., MAXDISPERSE);
- if (!(peer->flags & FLAG_PREEMPT))
+ 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))
}
/*
- * Respond to the peer evaluation produced by the
- * selection algorithm. If less than the outlieer level,
- * up the distance by three. If there are excess
- * associations less than the candidate level, up the
- * distance by two. If there are excess associations
- * otherwise, up the distance. If the distance exceeds
- * the threshold, off the rascal.
+ * Watch for timeout. If ephemeral or preemptable, toss
+ * the rascal; otherwise, bump the poll interval.
*/
- 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 += 1;
- } else {
- peer->unreach = 0;
- }
if (peer->unreach >= NTP_UNREACH) {
- if (peer->flags & FLAG_PREEMPT) {
+ if (peer->flags & FLAG_PREEMPT ||
+ !(peer->flags & FLAG_CONFIG)) {
+ peer_clear(peer, "TIME");
unpeer(peer);
return;
-
} else {
hpoll++;
}
* manycaster or it has already synchronized to us.
*/
if (sys_peer == NULL || hisstratum < sys_stratum ||
- (sys_cohort && hisstratum) == sys_stratum ||
+ (sys_cohort && hisstratum == sys_stratum) ||
rbufp->dstadr->addr_refid == pkt->refid)
return; /* no help */
if ((peer = newpeer(&rbufp->recv_srcadr,
rbufp->dstadr, MODE_CLIENT, hisversion,
NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_MCAST |
- FLAG_IBURST | FLAG_PREEMPT, MDF_BCLNT, 0,
- skeyid)) == NULL)
+ FLAG_IBURST, MDF_BCLNT, 0, skeyid)) ==
+ NULL)
return; /* system error */
-#ifdef OPENSSL
- if (skeyid <= NTP_MAXKEY)
- return; /* symmetric keys */
-
- if (crypto_recv(peer, rbufp) != XEVNT_OK)
- unpeer(peer); /* crypto failure */
-#endif /* OPENSSL */
return; /* hooray */
* If a two-way exchange is not possible,
* neither is Autokey.
*/
- if (skeyid <= NTP_MAXKEY) {
+ if (skeyid > NTP_MAXKEY) {
msyslog(LOG_INFO,
- "receive: broadcast requires two-way communication");
+ "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, FLAG_PREEMPT,
- MDF_BCLNT, 0, skeyid)) == NULL)
+ NTP_MINDPOLL, NTP_MAXDPOLL, 0, MDF_BCLNT, 0,
+ skeyid)) == NULL)
return; /* system error */
}
break;
if ((peer = newpeer(&rbufp->recv_srcadr,
rbufp->dstadr, MODE_PASSIVE, hisversion,
- NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_PREEMPT, MDF_UCAST,
- 0, skeyid)) == NULL)
+ NTP_MINDPOLL, NTP_MAXDPOLL, 0, MDF_UCAST, 0,
+ skeyid)) == NULL)
return; /* system error */
-
break;
/*
* Next comes a rigorous schedule of timestamp checking. If the
* transmit timestamp is zero, the server is horribly broken.
*/
- if (L_ISZERO(&p_xmt))
+ if (L_ISZERO(&p_xmt)) {
return; /* read rfc1305 */
/*
* packet is a replay. This prevents the bad guys from replaying
* the most recent packet, authenticated or not.
*/
- if (L_ISEQU(&peer->org, &p_xmt)) {
+ } else if (L_ISEQU(&peer->org, &p_xmt)) {
peer->flash |= TEST1;
peer->oldpkt++;
return; /* duplicate packet */
- }
+
/*
* If this is a broadcast mode packet, skip further checking.
*/
- if (hismode != MODE_BROADCAST) {
+ } else if (hismode != MODE_BROADCAST) {
if (L_ISZERO(&p_org))
peer->flash |= TEST3; /* protocol unsynch */
else if (!L_ISEQU(&p_org, &peer->xmt))
/*
* Update the origin and destination timestamps. If
- * unsynchronized or bogus abandon ship.
+ * unsynchronized or bogus abandon ship. If the crypto machine
+ * breaks, light the crypto bit and plaint the log.
*/
peer->org = p_xmt;
peer->rec = rbufp->recv_time;
- if (peer->flash)
+ if (peer->flash) {
+#ifdef OPENSSL
+ if (crypto_flags && (peer->flags & FLAG_SKEY)) {
+ rval = crypto_recv(peer, rbufp);
+ if (rval != XEVNT_OK)
+ peer->flash |= TEST9; /* crypto error */
+ }
+#endif /* OPENSSL */
return; /* unsynch */
+ }
/*
* 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 demobilize the association
- * and wait for better times.
+ * might have just changed keys. We reset the association
+ * and restart the protocol.
*/
if (is_authentic == AUTH_CRYPTO) {
peer_clear(peer, "AUTH");
* 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.
+ * 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);
return; /* bad auth */
}
* 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 go directly to jail.
+ * This is considered a permanant error, so light the crypto bit
+ * to suppress further requests.
*/
if (crypto_flags && (peer->flags & FLAG_SKEY)) {
peer->flash |= TEST8;
rval = crypto_recv(peer, rbufp);
if (rval != XEVNT_OK) {
- peer_clear(peer, "CRYP");
peer->flash |= TEST9; /* crypto error */
return;
} else if (hismode == MODE_SERVER) {
if (skeyid == peer->keyid)
peer->flash &= ~TEST8;
- } else if (!peer->flash & TEST8) {
+ } else if (!(peer->flash & TEST8)) {
peer->pkeyid = skeyid;
} else if ((ap = (struct autokey *)peer->recval.ptr) !=
NULL) {
peer->flash, stoa(&peer->srcadr));
return;
}
-
-#ifdef OPENSSL
- /*
- * If TEST8 is lit, the autokey sequence has broken, which
- * probably means the server has refreshed its private value.
- * Not to worry, reset and wait for the next time.
- */
- if (peer->flash & TEST8 && peer->crypto & CRYPTO_FLAG_AUTO) {
-#ifdef DEBUG
- if (debug)
- printf(
- "receive: flash auto %04x\n", peer->flash);
-#endif
- peer_clear(peer, "AUTO");
- }
-#endif /* OPENSSL */
}
record_raw_stats(&peer->srcadr, &peer->dstadr->sin, &p_org,
&p_rec, &p_xmt, &peer->rec);
peer->leap = pleap;
- peer->stratum = pstratum;
+ peer->stratum = min(pstratum, STRATUM_UNSPEC);
peer->pmode = pmode;
peer->ppoll = pkt->ppoll;
peer->precision = pkt->precision;
if (pleap == LEAP_NOTINSYNC || /* test 6 */
pstratum < sys_floor || pstratum >= sys_ceiling)
peer->flash |= TEST6; /* peer not synch */
- ci = p_xmt;
- L_SUB(&ci, &p_reftime);
if (p_del < 0 || p_disp < 0 || p_del / /* test 7 */
- 2 + p_disp >= MAXDISPERSE || L_ISNEG(&ci))
+ 2 + p_disp >= MAXDISPERSE || !L_ISHIS(&p_xmt, &p_reftime))
peer->flash |= TEST7; /* bad header */
/*
/*
* 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.
+ * the leap changes, we gotta reroll the keys. Except for
+ * reference clocks, the minimum dispersion increment is not
+ * less than sys_mindisp.
*/
case 1:
sys_leap = leap_next;
- sys_stratum = (u_char)(sys_peer->stratum + 1);
+ sys_stratum = sys_peer->stratum + 1;
if (sys_stratum == 1 || sys_stratum == STRATUM_UNSPEC)
sys_refid = sys_peer->refid;
else
sys_refid = addr2refid(&sys_peer->srcadr);
sys_reftime = sys_peer->rec;
- sys_rootdelay = sys_peer->rootdelay + sys_peer->delay;
+
+ /*
+ * 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 the peer root dispersion
+ * ignored.
+ */
dtemp = sys_peer->disp + clock_phi * (current_time -
- sys_peer->epoch) + sys_jitter +
+ sys_peer->update) + sys_jitter +
fabs(sys_peer->offset);
#ifdef REFCLOCK
if (!(sys_peer->flags & FLAG_REFCLOCK) && dtemp <
if (dtemp < sys_mindisp)
dtemp = sys_mindisp;
#endif /* REFCLOCK */
- sys_rootdispersion = sys_peer->rootdispersion + dtemp;
+ 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
memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO);
peer->estbdelay = sys_bdelay;
peer->ppoll = peer->maxpoll;
+ peer->hpoll = peer->minpoll;
peer->disp = MAXDISPERSE;
peer->jitter = LOGTOD(sys_precision);
for (i = 0; i < NTP_SHIFT; i++) {
*/
peer->nextdate = peer->update = peer->outdate = current_time;
if (initializing)
- peer->nextdate = current_time + peer_associations;
+ peer->nextdate += peer_associations;
+ else if (peer->hmode == MODE_PASSIVE)
+ peer->nextdate += RESP_DELAY;
else
- peer->nextdate = current_time + (ntp_random() & ((1 <<
- NTP_MINPOLL) - 1));
+ peer->nextdate += (ntp_random() & ((1 << NTP_MINDPOLL) -
+ 1));
#ifdef DEBUG
if (debug)
printf("peer_clear: at %ld next %ld assoc ID %d refid %s\n",
* NTP_MAXASSOC of them. Scan the list to find falsetickers, who
* leave the island immediately. The TRUE peer is alwasy a
* truechimer. We must leave at least one peer to collect the
- * million bucks.
+ * 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))
+ high) && !(peer->flags & FLAG_TRUE) &&
+ !(sys_stratum >= sys_orphan && peer->stratum <
+ sys_orphan))
continue;
peer->status = CTL_PST_SEL_DISTSYSPEER;
nlist = 1;
} else {
if (osys_peer != NULL) {
- sys_poll = NTP_MINPOLL;
NLOG(NLOG_SYNCSTATUS)
msyslog(LOG_INFO,
"no servers reachable");
* stratum. Note that the head of the list is at the lowest
* stratum and that unsynchronized peers cannot survive this
* far.
+ *
+ * In orphan mode the prefer peer is determined as the minimum
+ * root delay of the available peers. In normal mode the prefer
+ * peer is designated in the configuration file.
*/
leap_next = 0;
for (i = 0; i < nlist; i++) {
} else {
sys_peer = sys_prefer;
sys_peer->status = CTL_PST_SEL_SYSPEER;
- sys_offset = sys_peer->offset;
+ if (peer->stratum >= sys_orphan &&
+ sys_orphandelay < sys_peer->rootdelay)
+ sys_offset = 0;
+ else
+ sys_offset = sys_peer->offset;
sys_jitter = sys_peer->jitter;
#ifdef DEBUG
if (debug > 1)
struct peer *peer
)
{
+ double dist;
+
/*
* Careful squeak here. The value returned must be greater than
- * the minimum root distance in order to avoid clockhop with
- * highly precise reference clocks.
+ * 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) + peer->jitter);
+ (current_time - peer->update) + peer->jitter;
+ return (dist);
}
/*
* If the crypto is broken, don't make it worse. Otherwise,
* initialize the header fields.
*/
- if (peer->flash & TEST9)
- return;
-
xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, peer->version,
peer->hmode);
xpkt.stratum = STRATUM_TO_PKT(sys_stratum);
xpkt.ppoll = peer->hpoll;
xpkt.precision = sys_precision;
- xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
+ if (sys_stratum >= sys_orphan)
+ xpkt.rootdelay = HTONS_FP(DTOFP(sys_orphandelay));
+ else
+ xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
xpkt.rootdispersion = HTONS_FP(DTOUFP(sys_rootdispersion));
xpkt.refid = sys_refid;
HTONL_FP(&sys_reftime, &xpkt.reftime);
* 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 set, don't send requests.
*/
case MODE_ACTIVE:
case MODE_PASSIVE:
+ if (peer->flash & TEST9)
+ break;
+ /*
+ * Parameter and certificate.
+ */
if (!peer->crypto)
exten = crypto_args(peer, CRYPTO_ASSOC,
sys_hostname);
* 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->flash & TEST9)
+ break;
+ /*
+ * Parameter and certificate.
+ */
if (!peer->crypto)
exten = crypto_args(peer, CRYPTO_ASSOC,
sys_hostname);
}
/*
- * Build the extension fields if available. If an error
- * occured, the crypto machinery broke or was
- * misconfigured, so plaint the log and douse the
- * boiler.
+ * 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);
peer->cmmd = NULL;
}
if (exten != NULL) {
- if (exten->opcode != 0) {
+ if (exten->opcode != 0)
sendlen += crypto_xmit(&xpkt,
&peer->srcadr, sendlen, exten, 0);
- free(exten);
- } else {
- peer_clear(peer, "CRYP");
+ if (ntohl(exten->opcode) & CRYPTO_ERROR) {
peer->flash |= TEST9; /* crypto error */
- msyslog(LOG_INFO,
- "transmit: crypto error for %s",
- stoa(&peer->srcadr));
free(exten);
return;
}
+ free(exten);
}
/*
* If extension fields are present, we must use a
- * private cookie value of zero. 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) {
- peer_clear(peer, "NKEY");
+ msyslog(LOG_INFO, "transmit: %s key %u not found",
+ stoa(&peer->srcadr), xkeyid);
peer->flash |= TEST9; /* no key found */
- msyslog(LOG_INFO, "transmit: key %u not found for %s",
- xkeyid, stoa(&peer->srcadr));
return;
}
sendlen += authlen;
}
xpkt.ppoll = rpkt->ppoll;
xpkt.precision = sys_precision;
- xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
- xpkt.rootdispersion =
- HTONS_FP(DTOUFP(sys_rootdispersion));
+ if (sys_stratum >= sys_orphan)
+ xpkt.rootdelay = HTONS_FP(DTOFP(sys_orphandelay));
+ else
+ xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
+ xpkt.rootdispersion = HTONS_FP(DTOUFP(sys_rootdispersion));
HTONL_FP(&sys_reftime, &xpkt.reftime);
xpkt.org = rpkt->xmt;
HTONL_FP(&rbufp->recv_time, &xpkt.rec);
* A peer is unfit for synchronization if
* > TEST10 bad leap or stratum below floor or at or above ceiling
* > TEST11 root distance exceeded
- * > TEST12 a synchronization loop would form
+ * > TEST12 a direct or indirect synchronization loop would form
* > TEST13 unreachable or noselect
*/
int /* FALSE if fit, TRUE if unfit */
int rval = 0;
if (peer->leap == LEAP_NOTINSYNC || peer->stratum < sys_floor ||
- peer->stratum >= sys_ceiling)
+ peer->stratum >= sys_ceiling || (sys_stratum < sys_orphan &&
+ peer->stratum >= sys_orphan))
rval |= TEST10; /* stratum out of bounds */
if (root_distance(peer) >= sys_maxdist + clock_phi *
ULOGTOD(sys_poll))
rval |= TEST11; /* distance exceeded */
- if (peer->stratum > 1 && peer->dstadr->addr_refid ==
- peer->refid)
+ if (peer->stratum > 1 && (peer->refid ==
+ peer->dstadr->addr_refid || peer->refid == sys_refid))
rval |= TEST12; /* synch loop */
if (!peer->reach || peer->flags & FLAG_NOSELECT)
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;
sys_ceiling = (int)dvalue;
break;
+ /*
+ * Set orphan stratum.
+ */
+ case PROTO_ORPHAN:
+ sys_orphan = (int)dvalue;
+ break;
+
/*
* Set cohort switch.
*/