#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "ntpd.h"
#include "ntp_stdlib.h"
#include "ntp_unixtime.h"
#include "ntp_control.h"
#include "ntp_string.h"
#include <stdio.h>
#ifdef HAVE_LIBSCF_H
#include <libscf.h>
#include <unistd.h>
#endif
#if defined(VMS) && defined(VMS_LOCALUNIT)
#include "ntp_refclock.h"
#endif
#define AUTH(x, y) ((x) ? (y) == AUTH_OK : (y) == AUTH_OK || \
(y) == AUTH_NONE)
#define AUTH_NONE 0
#define AUTH_OK 1
#define AUTH_ERROR 2
#define AUTH_CRYPTO 3
#define NTP_IBURST 6
#define RESP_DELAY 1
u_char sys_leap;
u_char sys_stratum;
s_char sys_precision;
double sys_rootdelay;
double sys_rootdisp;
u_int32 sys_refid;
l_fp sys_reftime;
struct peer *sys_peer;
int sys_bclient;
double sys_bdelay;
int sys_authenticate;
l_fp sys_authdelay;
double sys_offset;
double sys_mindisp = MINDISPERSE;
double sys_maxdist = MAXDISTANCE;
double sys_jitter;
u_long sys_epoch;
static double sys_clockhop;
int leap_tai;
u_long leap_sec;
u_long leap_peers;
u_long leap_expire;
static int leap_vote;
keyid_t sys_private;
int sys_manycastserver;
int peer_ntpdate;
int sys_survivors;
int sys_floor = 0;
int sys_ceiling = STRATUM_UNSPEC;
int sys_minsane = 1;
int sys_minclock = NTP_MINCLOCK;
int sys_maxclock = NTP_MAXCLOCK;
int sys_cohort = 0;
int sys_orphan = STRATUM_UNSPEC + 1;
int sys_beacon = BEACON;
int sys_ttlmax;
u_char sys_ttl[MAX_TTL];
u_long sys_stattime;
u_long sys_received;
u_long sys_processed;
u_long sys_newversion;
u_long sys_oldversion;
u_long sys_restricted;
u_long sys_badlength;
u_long sys_badauth;
u_long sys_declined;
u_long sys_limitrejected;
u_long sys_kodsent;
static double root_distance (struct peer *);
static void clock_combine (struct peer **, int);
static void peer_xmit (struct peer *);
static void fast_xmit (struct recvbuf *, int, keyid_t,
int);
static void clock_update (struct peer *);
static int default_get_precision (void);
static int peer_unfit (struct peer *);
void
transmit(
struct peer *peer
)
{
int hpoll;
hpoll = peer->hpoll;
if (peer->cast_flags & (MDF_BCAST | MDF_MCAST)) {
peer->outdate = current_time;
if (sys_leap != LEAP_NOTINSYNC)
peer_xmit(peer);
poll_update(peer, hpoll);
return;
}
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_associations < sys_maxclock) {
if (peer->ttl < sys_ttlmax)
peer->ttl++;
peer_xmit(peer);
}
peer->unreach++;
poll_update(peer, hpoll);
return;
}
if (peer->burst == 0) {
u_char oreach;
oreach = peer->reach;
peer->outdate = current_time;
peer->unreach++;
peer->reach <<= 1;
if (!(peer->reach & 0x0f))
clock_filter(peer, 0., 0., MAXDISPERSE);
if (!peer->reach) {
if (oreach)
report_event(PEVNT_UNREACH, peer, NULL);
if ((peer->flags & FLAG_IBURST) &&
peer->retry == 0)
peer->retry = NTP_RETRY;
} else {
hpoll = sys_poll;
if (!(peer->flags & FLAG_PREEMPT &&
peer->hmode == MODE_CLIENT))
peer->unreach = 0;
if ((peer->flags & FLAG_BURST) && peer->retry ==
0 && !peer_unfit(peer))
peer->retry = NTP_RETRY;
}
if (peer->unreach >= NTP_UNREACH) {
hpoll++;
if (peer->flags & FLAG_PREEMPT) {
report_event(PEVNT_RESTART, peer,
"timeout");
if (peer->hmode != MODE_CLIENT) {
peer_clear(peer, "TIME");
unpeer(peer);
return;
}
if (peer_associations > sys_maxclock &&
score_all(peer)) {
peer_clear(peer, "TIME");
unpeer(peer);
return;
}
}
}
} else {
peer->burst--;
if (peer->burst == 0) {
if (mode_ntpdate) {
peer_ntpdate--;
if (peer_ntpdate == 0) {
msyslog(LOG_NOTICE,
"ntpd: no servers found");
printf(
"ntpd: no servers found\n");
exit (0);
}
}
}
}
if (peer->retry > 0)
peer->retry--;
if (peer->hmode != MODE_BCLIENT)
peer_xmit(peer);
poll_update(peer, hpoll);
}
void
receive(
struct recvbuf *rbufp
)
{
register struct peer *peer;
register struct pkt *pkt;
int hisversion;
int hisleap;
int hismode;
int hisstratum;
int restrict_mask;
int has_mac;
int authlen;
int is_authentic = 0;
int retcode = AM_NOMATCH;
keyid_t skeyid = 0;
u_int32 opcode = 0;
sockaddr_u *dstadr_sin;
struct peer *peer2;
l_fp p_org;
l_fp p_rec;
l_fp p_xmt;
#ifdef OPENSSL
struct autokey *ap;
int rval;
keyid_t pkeyid = 0, tkeyid = 0;
#endif
#ifdef HAVE_NTP_SIGND
static unsigned char zero_key[16];
#endif
sys_received++;
if (SRCPORT(&rbufp->recv_srcadr) < NTP_PORT) {
sys_badlength++;
return;
}
restrict_mask = restrictions(&rbufp->recv_srcadr);
#ifdef DEBUG
if (debug > 1)
printf("receive: at %ld %s<-%s flags %x restrict %03x\n",
current_time, stoa(&rbufp->dstadr->sin),
stoa(&rbufp->recv_srcadr),
rbufp->dstadr->flags, restrict_mask);
#endif
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 (restrict_mask & RES_IGNORE) {
sys_restricted++;
return;
}
if (hismode == MODE_PRIVATE) {
if (restrict_mask & RES_NOQUERY) {
sys_restricted++;
return;
}
process_private(rbufp, ((restrict_mask &
RES_NOMODIFY) == 0));
return;
}
if (hismode == MODE_CONTROL) {
if (restrict_mask & RES_NOQUERY) {
sys_restricted++;
return;
}
process_control(rbufp, restrict_mask);
return;
}
if (restrict_mask & RES_DONTSERVE) {
sys_restricted++;
return;
}
if (restrict_mask & RES_TIMEOUT) {
if ((double)ntp_random() / 0x7fffffff < .1) {
sys_restricted++;
return;
}
}
if (hisversion == NTP_VERSION) {
sys_newversion++;
} else if (!(restrict_mask & RES_VERSION) && hisversion >=
NTP_OLDVERSION) {
sys_oldversion++;
} else {
sys_badlength++;
return;
}
if (hismode == MODE_UNSPEC) {
if (hisversion == NTP_OLDVERSION) {
hismode = MODE_CLIENT;
} else {
sys_badlength++;
return;
}
}
authlen = LEN_PKT_NOMAC;
has_mac = rbufp->recv_length - authlen;
while (has_mac != 0) {
u_int32 len;
if (has_mac % 4 != 0 || has_mac < MIN_MAC_LEN) {
sys_badlength++;
return;
}
if (has_mac <= MAX_MAC_LEN) {
skeyid = ntohl(((u_int32 *)pkt)[authlen / 4]);
break;
} else {
opcode = ntohl(((u_int32 *)pkt)[authlen / 4]);
len = opcode & 0xffff;
if (len % 4 != 0 || len < 4 || len + authlen >
rbufp->recv_length) {
sys_badlength++;
return;
}
authlen += len;
has_mac -= len;
}
}
if (restrict_mask & RES_DONTTRUST && has_mac == 0) {
sys_restricted++;
return;
}
restrict_mask = ntp_monitor(rbufp, restrict_mask);
if (restrict_mask & RES_LIMITED) {
sys_limitrejected++;
if (!(restrict_mask & RES_KOD) || hismode ==
MODE_BROADCAST)
return;
if (hismode == MODE_CLIENT)
fast_xmit(rbufp, MODE_SERVER, skeyid,
restrict_mask);
else
fast_xmit(rbufp, MODE_ACTIVE, skeyid,
restrict_mask);
return;
}
restrict_mask &= ~RES_KOD;
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);
if (has_mac == 0) {
restrict_mask &= ~RES_MSSNTP;
is_authentic = AUTH_NONE;
#ifdef DEBUG
if (debug)
printf(
"receive: at %ld %s<-%s mode %d len %d\n",
current_time, stoa(dstadr_sin),
stoa(&rbufp->recv_srcadr), hismode,
authlen);
#endif
} else if (has_mac == 4) {
restrict_mask &= ~RES_MSSNTP;
is_authentic = AUTH_CRYPTO;
#ifdef DEBUG
if (debug)
printf(
"receive: at %ld %s<-%s mode %d keyid %08x len %d auth %d\n",
current_time, stoa(dstadr_sin),
stoa(&rbufp->recv_srcadr), hismode, skeyid,
authlen + has_mac, is_authentic);
#endif
#ifdef HAVE_NTP_SIGND
} else if (has_mac == MAX_MD5_LEN && (restrict_mask & RES_MSSNTP) &&
(retcode == AM_FXMIT || retcode == AM_NEWPASS) &&
(memcmp(zero_key, (char *)pkt + authlen + 4, MAX_MD5_LEN - 4) ==
0)) {
is_authentic = AUTH_NONE;
#endif
} else {
restrict_mask &= ~RES_MSSNTP;
#ifdef OPENSSL
if (crypto_flags && skeyid > NTP_MAXKEY) {
if (has_mac < MAX_MD5_LEN) {
sys_badauth++;
return;
}
if (hismode == MODE_BROADCAST) {
if (crypto_flags && rbufp->dstadr ==
any_interface) {
sys_restricted++;
return;
}
pkeyid = 0;
if (!SOCK_UNSPEC(&rbufp->dstadr->bcast))
dstadr_sin =
&rbufp->dstadr->bcast;
} else if (peer == NULL) {
pkeyid = session_key(
&rbufp->recv_srcadr, dstadr_sin, 0,
sys_private, 0);
} else {
pkeyid = peer->pcookie;
}
if (authlen > LEN_PKT_NOMAC && pkeyid != 0) {
session_key(&rbufp->recv_srcadr,
dstadr_sin, skeyid, 0, 2);
tkeyid = session_key(
&rbufp->recv_srcadr, dstadr_sin,
skeyid, pkeyid, 0);
} else {
tkeyid = session_key(
&rbufp->recv_srcadr, dstadr_sin,
skeyid, pkeyid, 2);
}
}
#endif
if (!authdecrypt(skeyid, (u_int32 *)pkt, authlen,
has_mac))
is_authentic = AUTH_ERROR;
else
is_authentic = AUTH_OK;
#ifdef OPENSSL
if (crypto_flags && skeyid > NTP_MAXKEY)
authtrust(skeyid, 0);
#endif
#ifdef DEBUG
if (debug)
printf(
"receive: at %ld %s<-%s mode %d keyid %08x len %d auth %d\n",
current_time, stoa(dstadr_sin),
stoa(&rbufp->recv_srcadr), hismode, skeyid,
authlen + has_mac, is_authentic);
#endif
}
switch (retcode) {
case AM_FXMIT:
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);
sys_badauth++;
} else {
sys_restricted++;
}
return;
}
if (!sys_manycastserver) {
sys_restricted++;
return;
}
if (sys_leap == LEAP_NOTINSYNC || sys_stratum >=
hisstratum || (!sys_cohort && sys_stratum ==
hisstratum + 1) || rbufp->dstadr->addr_refid ==
pkt->refid) {
sys_declined++;
return;
}
if (AUTH(restrict_mask & RES_DONTTRUST, is_authentic))
fast_xmit(rbufp, MODE_SERVER, skeyid,
restrict_mask);
return;
case AM_MANYCAST:
if (!AUTH(sys_authenticate | (restrict_mask &
(RES_NOPEER | RES_DONTTRUST)), is_authentic)) {
sys_restricted++;
return;
}
if (hisleap == LEAP_NOTINSYNC || hisstratum <
sys_floor || hisstratum >= sys_ceiling) {
sys_declined++;
return;
}
if ((peer2 = findmanycastpeer(rbufp)) == NULL) {
sys_restricted++;
return;
}
if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr,
MODE_CLIENT, hisversion, NTP_MINDPOLL, NTP_MAXDPOLL,
FLAG_PREEMPT, MDF_UCAST | MDF_ACLNT, 0, skeyid)) ==
NULL) {
sys_declined++;
return;
}
if (peer2->flags & FLAG_IBURST)
peer->flags |= FLAG_IBURST;
peer->minpoll = peer2->minpoll;
peer->maxpoll = peer2->maxpoll;
break;
case AM_NEWBCL:
if (sys_bclient == 0) {
sys_restricted++;
return;
}
if (!AUTH(sys_authenticate | (restrict_mask &
(RES_NOPEER | RES_DONTTRUST)), is_authentic)) {
sys_restricted++;
return;
}
if (hisleap == LEAP_NOTINSYNC || hisstratum <
sys_floor || hisstratum >= sys_ceiling) {
sys_declined++;
return;
}
#ifdef OPENSSL
if (crypto_flags && skeyid > NTP_MAXKEY && (opcode &
0xffff0000) != (CRYPTO_ASSOC | CRYPTO_RESP)) {
sys_declined++;
return;
}
#endif
if (sys_bdelay != 0) {
#ifdef OPENSSL
if (crypto_flags && skeyid > NTP_MAXKEY) {
sys_restricted++;
return;
}
#endif
if ((peer = newpeer(&rbufp->recv_srcadr,
rbufp->dstadr, MODE_BCLIENT, hisversion,
pkt->ppoll, pkt->ppoll, 0, 0, 0,
skeyid)) == NULL) {
sys_restricted++;
return;
} else {
peer->delay = sys_bdelay;
peer->bias = -sys_bdelay / 2.;
}
break;
}
if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr,
MODE_CLIENT, hisversion, pkt->ppoll, pkt->ppoll,
FLAG_IBURST | FLAG_PREEMPT, MDF_BCLNT, 0,
skeyid)) == NULL) {
sys_restricted++;
return;
}
#ifdef OPENSSL
if (skeyid > NTP_MAXKEY)
crypto_recv(peer, rbufp);
#endif
return;
case AM_NEWPASS:
if (!AUTH(sys_authenticate | (restrict_mask &
(RES_NOPEER | RES_DONTTRUST)), is_authentic)) {
if (AUTH(restrict_mask & RES_DONTTRUST,
is_authentic)) {
fast_xmit(rbufp, MODE_PASSIVE, skeyid,
restrict_mask);
return;
}
if (is_authentic == AUTH_ERROR) {
fast_xmit(rbufp, MODE_ACTIVE, 0,
restrict_mask);
sys_restricted++;
}
}
if (hisleap != LEAP_NOTINSYNC && (hisstratum <
sys_floor || hisstratum >= sys_ceiling)) {
sys_declined++;
return;
}
if ((peer = newpeer(&rbufp->recv_srcadr,
rbufp->dstadr, MODE_PASSIVE, hisversion, pkt->ppoll,
NTP_MAXDPOLL, FLAG_PREEMPT, MDF_UCAST, 0,
skeyid)) == NULL) {
sys_declined++;
return;
}
break;
case AM_PROCPKT:
break;
case AM_ERR:
sys_declined++;
return;
default:
sys_declined++;
return;
}
#ifdef OPENSSL
if (is_authentic != AUTH_CRYPTO && (((peer->flags &
FLAG_SKEY) && skeyid <= NTP_MAXKEY) || (!(peer->flags &
FLAG_SKEY) && skeyid > NTP_MAXKEY))) {
sys_badauth++;
return;
}
#endif
peer->received++;
peer->flash &= ~PKT_TEST_MASK;
if (peer->flags & FLAG_XBOGUS) {
peer->flags &= ~FLAG_XBOGUS;
peer->flash |= TEST3;
}
if (L_ISZERO(&p_xmt)) {
peer->flash |= TEST3;
} else if (L_ISEQU(&peer->xmt, &p_xmt)) {
peer->flash |= TEST1;
peer->oldpkt++;
return;
} else if (hismode == MODE_BROADCAST) {
if (!L_ISZERO(&p_org) && !(peer->flags & FLAG_XB)) {
peer->flags |= FLAG_XB;
peer->aorg = p_xmt;
peer->borg = rbufp->recv_time;
report_event(PEVNT_XLEAVE, peer, NULL);
return;
}
} else if (peer->flip == 0) {
if (!L_ISEQU(&p_org, &peer->aorg)) {
peer->bogusorg++;
peer->flash |= TEST2;
if (!L_ISZERO(&peer->dst) && L_ISEQU(&p_org,
&peer->dst)) {
peer->flip = 1;
report_event(PEVNT_XLEAVE, peer, NULL);
}
} else {
L_CLR(&peer->aorg);
}
} else if (L_ISZERO(&p_org) || L_ISZERO(&p_rec) ||
L_ISZERO(&peer->dst)) {
peer->flash |= TEST3;
} else if (!L_ISZERO(&peer->dst) && !L_ISEQU(&p_org,
&peer->dst)) {
peer->bogusorg++;
peer->flags |= FLAG_XBOGUS;
peer->flash |= TEST2;
}
if (peer->flip == 0) {
if (hismode != MODE_BROADCAST)
peer->rec = p_xmt;
peer->dst = rbufp->recv_time;
}
peer->xmt = p_xmt;
if (is_authentic == AUTH_CRYPTO) {
report_event(PEVNT_AUTH, peer, "crypto_NAK");
peer->flash |= TEST5;
peer->badauth++;
if (peer->flags & FLAG_PREEMPT) {
unpeer(peer);
return;
}
#ifdef OPENSSL
if (peer->crypto)
peer_clear(peer, "AUTH");
#endif
return;
} else if (!AUTH(has_mac || (restrict_mask & RES_DONTTRUST),
is_authentic)) {
report_event(PEVNT_AUTH, peer, "digest");
peer->flash |= TEST5;
peer->badauth++;
if (hismode == MODE_ACTIVE || hismode == MODE_PASSIVE)
fast_xmit(rbufp, MODE_ACTIVE, 0, restrict_mask);
if (peer->flags & FLAG_PREEMPT) {
unpeer(peer);
return;
}
#ifdef OPENSSL
if (peer->crypto)
peer_clear(peer, "AUTH");
#endif
return;
}
peer->ppoll = max(peer->minpoll, pkt->ppoll);
if (hismode == MODE_SERVER && hisleap == LEAP_NOTINSYNC &&
hisstratum == STRATUM_UNSPEC && memcmp(&pkt->refid,
"RATE", 4) == 0) {
peer->selbroken++;
report_event(PEVNT_RATE, peer, NULL);
if (pkt->ppoll > peer->minpoll)
peer->minpoll = peer->ppoll;
peer->burst = peer->retry = 0;
peer->throttle = (NTP_SHIFT + 1) * (1 << peer->minpoll);
poll_update(peer, pkt->ppoll);
return;
}
peer->timereceived = current_time;
if (is_authentic == AUTH_OK)
peer->flags |= FLAG_AUTHENTIC;
else
peer->flags &= ~FLAG_AUTHENTIC;
#ifdef OPENSSL
if (peer->flags & FLAG_SKEY) {
ap = (struct autokey *)peer->recval.ptr;
if (ap != NULL) {
if (ap->seq > 0)
ap->seq--;
}
peer->flash |= TEST8;
rval = crypto_recv(peer, rbufp);
if (rval == XEVNT_OK) {
peer->unreach = 0;
} else {
if (rval == XEVNT_ERR) {
report_event(PEVNT_RESTART, peer,
"crypto error");
peer_clear(peer, "CRYP");
peer->flash |= TEST9;
if (peer->flags & FLAG_PREEMPT)
unpeer(peer);
}
return;
}
if (hismode == MODE_SERVER) {
if (skeyid == peer->keyid)
peer->flash &= ~TEST8;
} else if (!(peer->flash & TEST8)) {
peer->pkeyid = skeyid;
} else if (ap != NULL) {
int i;
for (i = 0; ; i++) {
if (tkeyid == peer->pkeyid ||
tkeyid == ap->key) {
peer->flash &= ~TEST8;
peer->pkeyid = skeyid;
ap->seq -= i;
break;
}
if (i > ap->seq) {
peer->crypto &=
~CRYPTO_FLAG_AUTO;
break;
}
tkeyid = session_key(
&rbufp->recv_srcadr, dstadr_sin,
tkeyid, pkeyid, 0);
}
if (peer->flash & TEST8)
report_event(PEVNT_AUTH, peer, "keylist");
}
if (!(peer->crypto & CRYPTO_FLAG_PROV))
peer->flash |= TEST8;
if (current_time > peer->refresh) {
report_event(PEVNT_RESTART, peer,
"crypto refresh");
peer_clear(peer, "TIME");
return;
}
}
#endif
process_packet(peer, pkt, rbufp->recv_length);
if (peer->flip != 0) {
peer->rec = p_rec;
peer->dst = rbufp->recv_time;
if (peer->nextdate - current_time < (1 << min(peer->ppoll,
peer->hpoll)) / 2)
peer->nextdate++;
else
peer->nextdate--;
}
}
void
process_packet(
register struct peer *peer,
register struct pkt *pkt,
u_int len
)
{
double t34, t21;
double p_offset, p_del, p_disp;
l_fp p_rec, p_xmt, p_org, p_reftime, ci;
u_char pmode, pleap, pstratum;
char statstr[NTP_MAXSTRLEN];
#ifdef ASSYM
int itemp;
double etemp, ftemp, td;
#endif
sys_processed++;
peer->processed++;
p_del = FPTOD(NTOHS_FP(pkt->rootdelay));
p_offset = 0;
p_disp = FPTOD(NTOHS_FP(pkt->rootdisp));
NTOHL_FP(&pkt->reftime, &p_reftime);
NTOHL_FP(&pkt->org, &p_org);
NTOHL_FP(&pkt->rec, &p_rec);
NTOHL_FP(&pkt->xmt, &p_xmt);
pmode = PKT_MODE(pkt->li_vn_mode);
pleap = PKT_LEAP(pkt->li_vn_mode);
pstratum = PKT_TO_STRATUM(pkt->stratum);
record_raw_stats(&peer->srcadr, peer->dstadr ?
&peer->dstadr->sin : NULL, &p_org, &p_rec, &p_xmt,
&peer->dst);
peer->leap = pleap;
peer->stratum = min(pstratum, STRATUM_UNSPEC);
peer->pmode = pmode;
peer->precision = pkt->precision;
peer->rootdelay = p_del;
peer->rootdisp = p_disp;
peer->refid = pkt->refid;
peer->reftime = p_reftime;
if (peer->retry > 0) {
peer->retry = 0;
if (peer->reach)
peer->burst = min(1 << (peer->hpoll -
peer->minpoll), NTP_SHIFT) - 1;
else
peer->burst = NTP_IBURST - 1;
if (peer->burst > 0)
peer->nextdate = current_time;
}
poll_update(peer, peer->hpoll);
if (pleap == LEAP_NOTINSYNC ||
pstratum < sys_floor || pstratum >= sys_ceiling)
peer->flash |= TEST6;
if (p_del / 2 + p_disp >= MAXDISPERSE)
peer->flash |= TEST7;
if (peer->flash & PKT_TEST_MASK) {
peer->seldisptoolarge++;
#ifdef DEBUG
if (debug)
printf("packet: flash header %04x\n",
peer->flash);
#endif
return;
}
if (!peer->reach) {
report_event(PEVNT_REACH, peer, NULL);
peer->timereachable = current_time;
}
peer->reach |= 1;
if (peer->flip != 0) {
ci = p_xmt;
L_SUB(&ci, &peer->dst);
LFPTOD(&ci, t34);
ci = p_rec;
if (peer->flip > 0)
L_SUB(&ci, &peer->borg);
else
L_SUB(&ci, &peer->aorg);
LFPTOD(&ci, t21);
p_del = t21 - t34;
p_offset = (t21 + t34) / 2.;
if (p_del < 0 || p_del > 1.) {
sprintf(statstr, "t21 %.6f t34 %.6f", t21, t34);
report_event(PEVNT_XERR, peer, statstr);
return;
}
} else if (peer->pmode == MODE_BROADCAST) {
if (peer->flags & FLAG_XB) {
ci = p_org;
L_SUB(&ci, &peer->aorg);
LFPTOD(&ci, t34);
ci = p_org;
L_SUB(&ci, &peer->borg);
LFPTOD(&ci, t21);
peer->aorg = p_xmt;
peer->borg = peer->dst;
if (t34 < 0 || t34 > 1.) {
sprintf(statstr,
"offset %.6f delay %.6f", t21, t34);
report_event(PEVNT_XERR, peer, statstr);
return;
}
p_offset = t21;
peer->xleave = t34;
} else {
ci = p_xmt;
L_SUB(&ci, &peer->dst);
LFPTOD(&ci, t34);
p_offset = t34;
}
if (peer->cast_flags & MDF_BCLNT) {
peer->cast_flags &= ~MDF_BCLNT;
peer->delay = (peer->offset - p_offset) * 2;
}
p_del = peer->delay;
p_offset += p_del / 2;
} else {
ci = p_xmt;
L_SUB(&ci, &peer->dst);
LFPTOD(&ci, t34);
ci = p_rec;
L_SUB(&ci, &p_org);
LFPTOD(&ci, t21);
p_del = fabs(t21 - t34);
p_offset = (t21 + t34) / 2.;
}
p_offset += peer->bias;
p_disp = LOGTOD(sys_precision) + LOGTOD(peer->precision) +
clock_phi * p_del;
#if ASSYM
if (peer->t21_last > 0 && peer->t34_bytes > 0) {
itemp = peer->t21_bytes - peer->t21_last;
if (itemp > 25) {
etemp = t21 - peer->t21;
if (fabs(etemp) > 1e-6) {
ftemp = itemp / etemp;
if (ftemp > 1000.)
peer->r21 = ftemp;
}
}
itemp = len - peer->t34_bytes;
if (itemp > 25) {
etemp = -t34 - peer->t34;
if (fabs(etemp) > 1e-6) {
ftemp = itemp / etemp;
if (ftemp > 1000.)
peer->r34 = ftemp;
}
}
}
peer->t21 = t21;
peer->t21_last = peer->t21_bytes;
peer->t34 = -t34;
peer->t34_bytes = len;
#ifdef DEBUG
if (debug > 1)
printf("packet: t21 %.9lf %d t34 %.9lf %d\n", peer->t21,
peer->t21_bytes, peer->t34, peer->t34_bytes);
#endif
if (peer->r21 > 0 && peer->r34 > 0 && p_del > 0) {
if (peer->pmode != MODE_BROADCAST)
td = (peer->r34 / (peer->r21 + peer->r34) -
.5) * p_del;
else
td = 0;
t21 -= td;
t34 -= td;
#ifdef DEBUG
if (debug > 1)
printf("packet: del %.6lf r21 %.1lf r34 %.1lf %.6lf\n",
p_del, peer->r21 / 1e3, peer->r34 / 1e3,
td);
#endif
}
#endif
clock_filter(peer, p_offset, p_del, p_disp);
if ((peer->cast_flags & MDF_BCLNT) && !(peer_unfit(peer) &
TEST11)) {
#ifdef OPENSSL
if (peer->flags & FLAG_SKEY) {
if (!(~peer->crypto & CRYPTO_FLAG_ALL))
peer->hmode = MODE_BCLIENT;
} else {
peer->hmode = MODE_BCLIENT;
}
#else
peer->hmode = MODE_BCLIENT;
#endif
}
}
static void
clock_update(
struct peer *peer
)
{
double dtemp;
l_fp now;
#ifdef HAVE_LIBSCF_H
char *fmri;
#endif
sys_peer = peer;
sys_epoch = peer->epoch;
if (sys_poll < peer->minpoll)
sys_poll = peer->minpoll;
if (sys_poll > peer->maxpoll)
sys_poll = peer->maxpoll;
poll_update(peer, sys_poll);
sys_stratum = min(peer->stratum + 1, STRATUM_UNSPEC);
if (peer->stratum == STRATUM_REFCLOCK ||
peer->stratum == STRATUM_UNSPEC)
sys_refid = peer->refid;
else
sys_refid = addr2refid(&peer->srcadr);
dtemp = sys_jitter + fabs(sys_offset) + peer->disp + clock_phi *
(current_time - peer->update);
sys_rootdisp = dtemp + peer->rootdisp;
sys_rootdelay = peer->delay + peer->rootdelay;
sys_reftime = peer->dst;
#ifdef DEBUG
if (debug)
printf(
"clock_update: at %lu sample %lu associd %d\n",
current_time, peer->epoch, peer->associd);
#endif
switch (local_clock(peer, sys_offset)) {
case -1:
#ifdef HAVE_LIBSCF_H
if ((fmri = getenv("SMF_FMRI")) != NULL) {
if (smf_maintain_instance(fmri, 0) < 0) {
printf("smf_maintain_instance: %s\n",
scf_strerror(scf_error()));
exit(1);
}
for (;;)
pause();
}
#endif
exit (-1);
case 2:
clear_all();
sys_leap = LEAP_NOTINSYNC;
sys_stratum = STRATUM_UNSPEC;
memcpy(&sys_refid, "STEP", 4);
sys_rootdelay = 0;
sys_rootdisp = 0;
L_CLR(&sys_reftime);
sys_jitter = LOGTOD(sys_precision);
leapsec = 0;
break;
case 1:
if (sys_leap == LEAP_NOTINSYNC) {
sys_leap = LEAP_NOWARNING;
#ifdef OPENSSL
if (crypto_flags)
crypto_update();
#endif
}
get_systime(&now);
if (leap_sec > 0) {
if (leap_sec > now.l_ui) {
sys_tai = leap_tai - 1;
if (leapsec == 0)
report_event(EVNT_ARMED, NULL,
NULL);
leapsec = leap_sec - now.l_ui;
} else {
sys_tai = leap_tai;
}
break;
} else if (leap_vote > sys_survivors / 2) {
leap_peers = now.l_ui + leap_month(now.l_ui);
if (leap_peers > now.l_ui) {
if (leapsec == 0)
report_event(PEVNT_ARMED, peer,
NULL);
leapsec = leap_peers - now.l_ui;
}
} else if (leapsec > 0) {
report_event(EVNT_DISARMED, NULL, NULL);
leapsec = 0;
}
break;
default:
break;
}
}
void
poll_update(
struct peer *peer,
int mpoll
)
{
int hpoll, minpkt;
u_long next, utemp;
if (peer->cast_flags & MDF_BCLNT)
hpoll = peer->minpoll;
else
hpoll = max(min(peer->maxpoll, mpoll), peer->minpoll);
#ifdef OPENSSL
if ((peer->flags & FLAG_SKEY) && hpoll != peer->hpoll)
key_expire(peer);
#endif
peer->hpoll = hpoll;
minpkt = 1 << ntp_minpkt;
utemp = current_time + max(peer->throttle - (NTP_SHIFT - 1) *
(1 << peer->minpoll), minpkt);
if (peer->burst > 0) {
if (peer->nextdate > current_time)
return;
#ifdef REFCLOCK
else if (peer->flags & FLAG_REFCLOCK)
peer->nextdate = current_time + RESP_DELAY;
#endif
else {
#if __APPLE__
peer->nextdate = current_time + RESP_DELAY;
#else // !__APPLE__
peer->nextdate = utemp;
#endif // __APPLE__
}
#ifdef OPENSSL
} else if (peer->cmmd != NULL) {
if (peer->nextdate > current_time) {
if (peer->nextdate + minpkt != utemp)
peer->nextdate = utemp;
} else {
peer->nextdate = utemp;
}
#endif
} else {
if (peer->retry > 0)
hpoll = peer->minpoll;
else if (!(peer->reach))
hpoll = peer->hpoll;
else
hpoll = min(peer->ppoll, peer->hpoll);
#ifdef REFCLOCK
if (peer->flags & FLAG_REFCLOCK)
next = 1 << hpoll;
else
next = ((0x1000UL | (ntp_random() & 0x0ff)) <<
hpoll) >> 12;
#else
next = ((0x1000UL | (ntp_random() & 0x0ff)) << hpoll) >>
12;
#endif
next += peer->outdate;
if (next > utemp)
peer->nextdate = next;
else
peer->nextdate = utemp;
hpoll = peer->throttle - (1 << peer->minpoll);
if (hpoll > 0)
peer->nextdate += minpkt;
}
#ifdef DEBUG
if (debug > 1)
printf("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,
utemp - current_time, peer->nextdate -
current_time);
#endif
}
void
peer_clear(
struct peer *peer,
char *ident
)
{
int i;
#ifdef OPENSSL
key_expire(peer);
if (peer->iffval != NULL)
BN_free(peer->iffval);
value_free(&peer->cookval);
value_free(&peer->recval);
value_free(&peer->encrypt);
value_free(&peer->sndval);
if (peer->cmmd != NULL)
free(peer->cmmd);
if (peer->subject != NULL)
free(peer->subject);
if (peer->issuer != NULL)
free(peer->issuer);
#endif
int oldburst = (peer->burst > 0);
memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO);
peer->ppoll = peer->maxpoll;
peer->hpoll = peer->minpoll;
peer->disp = MAXDISPERSE;
peer->flash = peer_unfit(peer);
peer->jitter = LOGTOD(sys_precision);
if (oldburst) {
peer->burst = NSTAGE;
}
if (peer->flags & FLAG_XLEAVE)
peer->flip = 1;
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;
peer->stratum = STRATUM_UNSPEC;
memcpy(&peer->refid, ident, 4);
}
#else
peer->leap = LEAP_NOTINSYNC;
peer->stratum = STRATUM_UNSPEC;
memcpy(&peer->refid, ident, 4);
#endif
peer->nextdate = peer->update = peer->outdate = current_time;
if (initializing) {
peer->nextdate += peer_associations;
} else if (peer->hmode == MODE_PASSIVE) {
peer->nextdate += 1 << ntp_minpkt;
} else {
peer->nextdate += ntp_random() % peer_associations;
}
#ifdef OPENSSL
peer->refresh = current_time + (1 << NTP_REFRESH);
#endif
#ifdef DEBUG
if (debug)
printf(
"peer_clear: at %ld next %ld associd %d refid %s\n",
current_time, peer->nextdate, peer->associd,
ident);
#endif
}
void
clock_filter(
struct peer *peer,
double sample_offset,
double sample_delay,
double sample_disp
)
{
double dst[NTP_SHIFT];
int ord[NTP_SHIFT];
int i, j, k, m;
double dtemp, etemp;
char tbuf[80];
j = peer->filter_nextpt;
peer->filter_offset[j] = sample_offset;
peer->filter_delay[j] = sample_delay;
peer->filter_disp[j] = sample_disp;
peer->filter_epoch[j] = current_time;
j = (j + 1) % NTP_SHIFT;
peer->filter_nextpt = j;
dtemp = clock_phi * (current_time - peer->update);
peer->update = current_time;
for (i = NTP_SHIFT - 1; i >= 0; i--) {
if (i != 0)
peer->filter_disp[j] += dtemp;
if (peer->filter_disp[j] >= MAXDISPERSE) {
peer->filter_disp[j] = MAXDISPERSE;
dst[i] = MAXDISPERSE;
} else if (peer->update - peer->filter_epoch[j] >
ULOGTOD(allan_xpt)) {
dst[i] = peer->filter_delay[j] +
peer->filter_disp[j];
} else {
dst[i] = peer->filter_delay[j];
}
ord[i] = j;
j = (j + 1) % NTP_SHIFT;
}
if (sys_leap != LEAP_NOTINSYNC) {
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;
}
}
}
}
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] >=
sys_maxdist))
continue;
m++;
}
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)
peer->jitter += DIFF(peer->filter_offset[j],
peer->filter_offset[k]);
}
if (m == 0)
return;
etemp = fabs(peer->offset - peer->filter_offset[k]);
peer->offset = peer->filter_offset[k];
peer->delay = peer->filter_delay[k];
if (m > 1)
peer->jitter /= m - 1;
peer->jitter = max(SQRT(peer->jitter), LOGTOD(sys_precision));
if (peer->disp < sys_maxdist && peer->filter_disp[k] <
sys_maxdist && etemp > CLOCK_SGATE * peer->jitter &&
peer->filter_epoch[k] - peer->epoch < 2. *
ULOGTOD(peer->hpoll)) {
snprintf(tbuf, sizeof(tbuf), "%.6f s", etemp);
report_event(PEVNT_POPCORN, peer, tbuf);
return;
}
if (peer->filter_epoch[k] <= peer->epoch) {
#if DEBUG
if (debug)
printf("clock_filter: old sample %lu\n", current_time -
peer->filter_epoch[k]);
#endif
return;
}
peer->epoch = peer->filter_epoch[k];
record_peer_stats(&peer->srcadr, ctlpeerstatus(peer),
peer->offset, peer->delay, peer->disp, peer->jitter);
#ifdef DEBUG
if (debug)
printf(
"clock_filter: n %d off %.6f del %.6f dsp %.6f jit %.6f\n",
m, peer->offset, peer->delay, peer->disp,
peer->jitter);
#endif
if (peer->burst == 0 || sys_leap == LEAP_NOTINSYNC)
clock_select();
}
void
clock_select(void)
{
struct peer *peer;
int i, j, k, n;
int nlist, nl3;
int allow, osurv;
double d, e, f, g;
double high, low;
double seljitter;
double synch[NTP_MAXASSOC], error[NTP_MAXASSOC];
double orphdist = 1e10;
struct peer *osys_peer = NULL;
struct peer *sys_prefer = NULL;
struct peer *typesystem = NULL;
struct peer *typeorphan = NULL;
#ifdef REFCLOCK
struct peer *typeacts = NULL;
struct peer *typelocal = NULL;
struct peer *typepps = NULL;
#endif
static int list_alloc = 0;
static struct endpoint *endpoint = NULL;
static int *indx = NULL;
static struct peer **peer_list = NULL;
static u_int endpoint_size = 0;
static u_int indx_size = 0;
static u_int peer_list_size = 0;
osys_peer = sys_peer;
osurv = sys_survivors;
sys_survivors = 0;
#ifdef LOCKCLOCK
sys_leap = LEAP_NOTINSYNC;
sys_stratum = STRATUM_UNSPEC;
memcpy(&sys_refid, "DOWN", 4);
#endif
nlist = 0;
for (n = 0; n < NTP_HASH_SIZE; n++)
nlist += peer_hash_count[n];
if (nlist > list_alloc) {
if (list_alloc > 0) {
free(endpoint);
free(indx);
free(peer_list);
}
while (list_alloc < nlist) {
list_alloc += 5;
endpoint_size += 5 * 3 * sizeof(*endpoint);
indx_size += 5 * 3 * sizeof(*indx);
peer_list_size += 5 * sizeof(*peer_list);
}
endpoint = (struct endpoint *)emalloc(endpoint_size);
indx = (int *)emalloc(indx_size);
peer_list = (struct peer **)emalloc(peer_list_size);
}
nlist = nl3 = 0;
for (n = 0; n < NTP_HASH_SIZE; n++) {
for (peer = peer_hash[n]; peer != NULL; peer =
peer->next) {
peer->flags &= ~FLAG_SYSPEER;
peer->status = CTL_PST_SEL_REJECT;
if (peer_unfit(peer))
continue;
if (peer->stratum == sys_orphan) {
double ftemp;
ftemp = addr2refid(&peer->srcadr);
if (ftemp < orphdist) {
typeorphan = peer;
orphdist = ftemp;
}
continue;
}
#ifdef REFCLOCK
switch (peer->refclktype) {
case REFCLK_LOCALCLOCK:
if (typelocal == NULL &&
!(peer->flags & FLAG_PREFER))
typelocal = peer;
continue;
case REFCLK_ACTS:
if (typeacts == NULL &&
!(peer->flags & FLAG_PREFER))
typeacts = peer;
continue;
}
#endif
peer->status = CTL_PST_SEL_SANE;
peer_list[nlist++] = peer;
e = peer->offset;
f = root_distance(peer);
e = e + f;
for (i = nl3 - 1; i >= 0; i--) {
if (e >= endpoint[indx[i]].val)
break;
indx[i + 3] = indx[i];
}
indx[i + 3] = nl3;
endpoint[nl3].type = 1;
endpoint[nl3++].val = e;
e = e - f;
for (; i >= 0; i--) {
if (e >= endpoint[indx[i]].val)
break;
indx[i + 2] = indx[i];
}
indx[i + 2] = nl3;
endpoint[nl3].type = 0;
endpoint[nl3++].val = e;
e = e - f;
for (; i >= 0; i--) {
if (e >= endpoint[indx[i]].val)
break;
indx[i + 1] = indx[i];
}
indx[i + 1] = nl3;
endpoint[nl3].type = -1;
endpoint[nl3++].val = e;
}
}
#ifdef DEBUG
if (debug > 2)
for (i = 0; i < nl3; i++)
printf("select: endpoint %2d %.6f\n",
endpoint[indx[i]].type,
endpoint[indx[i]].val);
#endif
low = 1e9;
high = -1e9;
for (allow = 0; 2 * allow < nlist; allow++) {
int found;
found = 0;
n = 0;
for (i = 0; i < nl3; i++) {
low = endpoint[indx[i]].val;
n -= endpoint[indx[i]].type;
if (n >= nlist - allow)
break;
if (endpoint[indx[i]].type == 0)
found++;
}
n = 0;
for (j = nl3 - 1; j >= 0; j--) {
high = endpoint[indx[j]].val;
n += endpoint[indx[j]].type;
if (n >= nlist - allow)
break;
if (endpoint[indx[j]].type == 0)
found++;
}
if (found > allow)
continue;
if (high > low)
break;
}
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))
continue;
#ifdef REFCLOCK
if (peer->flags & FLAG_PPS) {
if (typepps == NULL)
typepps = peer;
continue;
}
#endif
d = (root_distance(peer) + clock_phi * (peer->nextdate -
current_time)) / sys_maxdist + peer->stratum;
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 (nlist == 0) {
error[0] = 0;
synch[0] = 0;
#ifdef REFCLOCK
if (typeacts != NULL) {
peer_list[0] = typeacts;
nlist = 1;
} else if (typelocal != NULL) {
peer_list[0] = typelocal;
nlist = 1;
}
#endif
if (typeorphan != NULL) {
peer_list[0] = typeorphan;
nlist = 1;
}
}
for (i = 0; i < nlist; i++) {
peer_list[i]->status = CTL_PST_SEL_SELCAND;
#ifdef DEBUG
if (debug > 1)
printf("select: survivor %s %f\n",
stoa(&peer_list[i]->srcadr), synch[i]);
#endif
}
seljitter = 0;
while (1) {
d = 1e9;
e = -1e9;
f = g = 0;
k = 0;
for (i = 0; i < nlist; i++) {
if (error[i] < d)
d = error[i];
f = 0;
if (nlist > 1) {
for (j = 0; j < nlist; j++)
f += DIFF(peer_list[j]->offset,
peer_list[i]->offset);
f = SQRT(f / (nlist - 1));
}
if (f * synch[i] > e) {
g = f;
e = f * synch[i];
k = i;
}
}
f = max(f, LOGTOD(sys_precision));
if (nlist <= sys_minsane || nlist <= sys_minclock) {
break;
} else if (f <= d || peer_list[k]->flags &
(FLAG_TRUE | FLAG_PREFER)) {
seljitter = f;
break;
}
#ifdef DEBUG
if (debug > 2)
printf(
"select: drop %s seljit %.6f jit %.6f\n",
ntoa(&peer_list[k]->srcadr), g, d);
#endif
if (nlist > sys_maxclock)
peer_list[k]->status = CTL_PST_SEL_EXCESS;
for (j = k + 1; j < nlist; j++) {
peer_list[j - 1] = peer_list[j];
synch[j - 1] = synch[j];
error[j - 1] = error[j];
}
nlist--;
}
leap_vote = 0;
for (i = 0; i < nlist; i++) {
peer = peer_list[i];
peer->unreach = 0;
peer->status = CTL_PST_SEL_SYNCCAND;
sys_survivors++;
if (peer->leap == LEAP_ADDSECOND) {
if (peer->flags & FLAG_REFCLOCK)
leap_vote = nlist;
else
leap_vote++;
}
if (peer->flags & FLAG_PREFER)
sys_prefer = peer;
}
if (nlist > 0 && nlist >= sys_minsane) {
double x;
typesystem = peer_list[0];
if (osys_peer == NULL || osys_peer == typesystem) {
sys_clockhop = 0;
} else if ((x = fabs(typesystem->offset -
osys_peer->offset)) < sys_mindisp) {
if (sys_clockhop == 0)
sys_clockhop = sys_mindisp;
else
sys_clockhop *= .5;
#ifdef DEBUG
if (debug)
printf("select: clockhop %d %.6f %.6f\n",
j, x, sys_clockhop);
#endif
if (fabs(x) < sys_clockhop)
typesystem = osys_peer;
else
sys_clockhop = 0;
} else {
sys_clockhop = 0;
}
}
if (typesystem != NULL) {
if (sys_prefer == NULL) {
typesystem->status = CTL_PST_SEL_SYSPEER;
clock_combine(peer_list, sys_survivors);
sys_jitter = SQRT(SQUARE(typesystem->jitter) +
SQUARE(sys_jitter) + SQUARE(seljitter));
} else {
typesystem = sys_prefer;
sys_clockhop = 0;
typesystem->status = CTL_PST_SEL_SYSPEER;
sys_offset = typesystem->offset;
sys_jitter = typesystem->jitter;
}
#ifdef DEBUG
if (debug)
printf("select: combine offset %.9f jitter %.9f\n",
sys_offset, sys_jitter);
#endif
}
#ifdef REFCLOCK
if (typepps != NULL && fabs(sys_offset < 0.4) &&
(typepps->refclktype != REFCLK_ATOM_PPS ||
(typepps->refclktype == REFCLK_ATOM_PPS && (sys_prefer !=
NULL || (typesystem == NULL && sys_minsane == 0))))) {
typesystem = typepps;
sys_clockhop = 0;
typesystem->status = CTL_PST_SEL_PPS;
sys_offset = typesystem->offset;
sys_jitter = typesystem->jitter;
#ifdef DEBUG
if (debug)
printf("select: pps offset %.9f jitter %.9f\n",
sys_offset, sys_jitter);
#endif
}
#endif
if (typesystem == NULL) {
if (osys_peer != NULL)
report_event(EVNT_NOPEER, NULL, NULL);
sys_peer = NULL;
return;
}
if (typesystem->epoch <= sys_epoch)
return;
if (osys_peer != typesystem)
report_event(PEVNT_NEWPEER, typesystem, NULL);
typesystem->flags |= FLAG_SYSPEER;
clock_update(typesystem);
}
static void
clock_combine(
struct peer **peers,
int npeers
)
{
int i;
double x, y, z, w;
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;
}
sys_offset = z / y;
sys_jitter = SQRT(w / y);
}
static double
root_distance(
struct peer *peer
)
{
double dtemp;
dtemp = (peer->delay + peer->rootdelay) / 2 + peer->disp +
peer->rootdisp + clock_phi * (current_time - peer->update) +
peer->jitter;
if (dtemp < sys_mindisp)
dtemp = sys_mindisp;
return (dtemp);
}
static void
peer_xmit(
struct peer *peer
)
{
struct pkt xpkt;
int sendlen, authlen;
keyid_t xkeyid = 0;
l_fp xmt_tx, xmt_ty;
if (!peer->dstadr)
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.refid = sys_refid;
xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
xpkt.rootdisp = HTONS_FP(DTOUFP(sys_rootdisp));
HTONL_FP(&sys_reftime, &xpkt.reftime);
HTONL_FP(&peer->rec, &xpkt.org);
HTONL_FP(&peer->dst, &xpkt.rec);
sendlen = LEN_PKT_NOMAC;
#ifdef OPENSSL
if (!(peer->flags & FLAG_SKEY) && peer->keyid == 0) {
#else
if (peer->keyid == 0) {
#endif
get_systime(&xmt_tx);
if (peer->flip == 0) {
peer->aorg = xmt_tx;
HTONL_FP(&xmt_tx, &xpkt.xmt);
} else {
if (peer->hmode == MODE_BROADCAST) {
HTONL_FP(&xmt_tx, &xpkt.xmt);
if (peer->flip > 0)
HTONL_FP(&peer->borg,
&xpkt.org);
else
HTONL_FP(&peer->aorg,
&xpkt.org);
} else {
if (peer->flip > 0)
HTONL_FP(&peer->borg,
&xpkt.xmt);
else
HTONL_FP(&peer->aorg,
&xpkt.xmt);
}
}
peer->t21_bytes = sendlen;
sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl],
&xpkt, sendlen);
peer->sent++;
peer->throttle += (1 << peer->minpoll) - 2;
get_systime(&xmt_ty);
if (peer->flip != 0) {
if (peer->flip > 0)
peer->aorg = xmt_ty;
else
peer->borg = xmt_ty;
peer->flip = -peer->flip;
}
L_SUB(&xmt_ty, &xmt_tx);
LFPTOD(&xmt_ty, peer->xleave);
#ifdef DEBUG
if (debug)
printf("transmit: at %ld %s->%s mode %d len %d\n",
current_time, peer->dstadr ?
stoa(&peer->dstadr->sin) : "-",
stoa(&peer->srcadr), peer->hmode, sendlen);
#endif
return;
}
#ifdef OPENSSL
if (peer->flags & FLAG_SKEY) {
struct exten *exten;
while (1) {
if (peer->keynumber == 0)
make_keylist(peer, peer->dstadr);
else
peer->keynumber--;
xkeyid = peer->keylist[peer->keynumber];
if (authistrusted(xkeyid))
break;
else
key_expire(peer);
}
peer->keyid = xkeyid;
exten = NULL;
switch (peer->hmode) {
case MODE_BROADCAST:
if (peer->flags & FLAG_ASSOC)
exten = crypto_args(peer, CRYPTO_AUTO |
CRYPTO_RESP, peer->associd, NULL);
else
exten = crypto_args(peer, CRYPTO_ASSOC |
CRYPTO_RESP, peer->associd, NULL);
break;
case MODE_ACTIVE:
case MODE_PASSIVE:
if (!peer->crypto)
exten = crypto_args(peer, CRYPTO_ASSOC,
peer->associd, sys_hostname);
else if (!(peer->crypto & CRYPTO_FLAG_CERT))
exten = crypto_args(peer, CRYPTO_CERT,
peer->associd, peer->issuer);
else if (!(peer->crypto & CRYPTO_FLAG_VRFY))
exten = crypto_args(peer,
crypto_ident(peer), peer->associd,
NULL);
else if (sys_leap != LEAP_NOTINSYNC &&
peer->leap != LEAP_NOTINSYNC &&
!(peer->crypto & CRYPTO_FLAG_COOK))
exten = crypto_args(peer, CRYPTO_COOK,
peer->associd, NULL);
else if (!(peer->crypto & CRYPTO_FLAG_AUTO))
exten = crypto_args(peer, CRYPTO_AUTO,
peer->associd, NULL);
else if (peer->flags & FLAG_ASSOC &&
peer->crypto & CRYPTO_FLAG_SIGN)
exten = crypto_args(peer, CRYPTO_AUTO |
CRYPTO_RESP, peer->assoc, NULL);
else if (sys_leap == LEAP_NOTINSYNC)
break;
else if (!(peer->crypto & CRYPTO_FLAG_SIGN))
exten = crypto_args(peer, CRYPTO_SIGN,
peer->associd, sys_hostname);
else if (!(peer->crypto & CRYPTO_FLAG_LEAP))
exten = crypto_args(peer, CRYPTO_LEAP,
peer->associd, NULL);
break;
case MODE_CLIENT:
if (!peer->crypto)
exten = crypto_args(peer, CRYPTO_ASSOC,
peer->associd, sys_hostname);
else if (!(peer->crypto & CRYPTO_FLAG_CERT))
exten = crypto_args(peer, CRYPTO_CERT,
peer->associd, peer->issuer);
else if (!(peer->crypto & CRYPTO_FLAG_VRFY))
exten = crypto_args(peer,
crypto_ident(peer), peer->associd,
NULL);
else if (!(peer->crypto & CRYPTO_FLAG_COOK))
exten = crypto_args(peer, CRYPTO_COOK,
peer->associd, NULL);
else if (!(peer->crypto & CRYPTO_FLAG_AUTO))
exten = crypto_args(peer, CRYPTO_AUTO,
peer->assoc, NULL);
else if (sys_leap == LEAP_NOTINSYNC)
break;
else if (!(peer->crypto & CRYPTO_FLAG_SIGN))
exten = crypto_args(peer, CRYPTO_SIGN,
peer->associd, sys_hostname);
else if (!(peer->crypto & CRYPTO_FLAG_LEAP))
exten = crypto_args(peer, CRYPTO_LEAP,
peer->associd, NULL);
break;
}
if (peer->cmmd != NULL) {
u_int32 temp32;
temp32 = CRYPTO_RESP;
peer->cmmd->opcode |= htonl(temp32);
sendlen += crypto_xmit(peer, &xpkt, NULL,
sendlen, peer->cmmd, 0);
free(peer->cmmd);
peer->cmmd = NULL;
}
if (exten != NULL) {
if (exten->opcode != 0)
sendlen += crypto_xmit(peer, &xpkt,
NULL, sendlen, exten, 0);
free(exten);
}
if (sendlen > LEN_PKT_NOMAC) {
session_key(&peer->dstadr->sin, &peer->srcadr,
xkeyid, 0, 2);
}
}
#endif
get_systime(&xmt_tx);
if (peer->flip == 0) {
peer->aorg = xmt_tx;
HTONL_FP(&xmt_tx, &xpkt.xmt);
} else {
if (peer->hmode == MODE_BROADCAST) {
HTONL_FP(&xmt_tx, &xpkt.xmt);
if (peer->flip > 0)
HTONL_FP(&peer->borg, &xpkt.org);
else
HTONL_FP(&peer->aorg, &xpkt.org);
} else {
if (peer->flip > 0)
HTONL_FP(&peer->borg, &xpkt.xmt);
else
HTONL_FP(&peer->aorg, &xpkt.xmt);
}
}
xkeyid = peer->keyid;
authlen = authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen);
if (authlen == 0) {
report_event(PEVNT_AUTH, peer, "no key");
peer->flash |= TEST5;
peer->badauth++;
return;
}
sendlen += authlen;
#ifdef OPENSSL
if (xkeyid > NTP_MAXKEY)
authtrust(xkeyid, 0);
#endif
if (sendlen > sizeof(xpkt)) {
msyslog(LOG_ERR, "proto: buffer overflow %u", sendlen);
exit (-1);
}
peer->t21_bytes = sendlen;
sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl], &xpkt,
sendlen);
peer->sent++;
peer->throttle += (1 << peer->minpoll) - 2;
get_systime(&xmt_ty);
if (peer->flip != 0) {
if (peer->flip > 0)
peer->aorg = xmt_ty;
else
peer->borg = xmt_ty;
peer->flip = -peer->flip;
}
L_SUB(&xmt_ty, &xmt_tx);
LFPTOD(&xmt_ty, peer->xleave);
#ifdef OPENSSL
#ifdef DEBUG
if (debug)
printf("transmit: at %ld %s->%s mode %d keyid %08x len %d index %d\n",
current_time, peer->dstadr ?
ntoa(&peer->dstadr->sin) : "-",
ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen,
peer->keynumber);
#endif
#else
#ifdef DEBUG
if (debug)
printf("transmit: at %ld %s->%s mode %d keyid %08x len %d\n",
current_time, peer->dstadr ?
ntoa(&peer->dstadr->sin) : "-",
ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen);
#endif
#endif
}
static void
fast_xmit(
struct recvbuf *rbufp,
int xmode,
keyid_t xkeyid,
int flags
)
{
struct pkt xpkt;
struct pkt *rpkt;
l_fp xmt_tx, xmt_ty;
int sendlen;
#ifdef OPENSSL
u_int32 temp32;
#endif
rpkt = &rbufp->recv_pkt;
if (rbufp->dstadr->flags & INT_MCASTOPEN)
rbufp->dstadr = findinterface(&rbufp->recv_srcadr);
if (flags & RES_KOD) {
sys_kodsent++;
xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC,
PKT_VERSION(rpkt->li_vn_mode), xmode);
xpkt.stratum = STRATUM_PKT_UNSPEC;
xpkt.ppoll = max(rpkt->ppoll, ntp_minpoll);
memcpy(&xpkt.refid, "RATE", 4);
xpkt.org = rpkt->xmt;
xpkt.rec = rpkt->xmt;
xpkt.xmt = rpkt->xmt;
} else {
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.ppoll = max(rpkt->ppoll, ntp_minpoll);
xpkt.precision = sys_precision;
xpkt.refid = sys_refid;
xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay));
xpkt.rootdisp = HTONS_FP(DTOUFP(sys_rootdisp));
HTONL_FP(&sys_reftime, &xpkt.reftime);
xpkt.org = rpkt->xmt;
HTONL_FP(&rbufp->recv_time, &xpkt.rec);
get_systime(&xmt_tx);
HTONL_FP(&xmt_tx, &xpkt.xmt);
}
#ifdef HAVE_NTP_SIGND
if (flags & RES_MSSNTP) {
send_via_ntp_signd(rbufp, xmode, xkeyid, flags, &xpkt);
return;
}
#endif
sendlen = LEN_PKT_NOMAC;
if (rbufp->recv_length == sendlen) {
sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, &xpkt,
sendlen);
#ifdef DEBUG
if (debug)
printf(
"transmit: at %ld %s->%s mode %d len %d\n",
current_time, stoa(&rbufp->dstadr->sin),
stoa(&rbufp->recv_srcadr), xmode, sendlen);
#endif
return;
}
#ifdef OPENSSL
if (xkeyid > NTP_MAXKEY) {
keyid_t cookie;
cookie = session_key(&rbufp->recv_srcadr,
&rbufp->dstadr->sin, 0, sys_private, 0);
if (rbufp->recv_length > sendlen + MAX_MAC_LEN) {
session_key(&rbufp->dstadr->sin,
&rbufp->recv_srcadr, xkeyid, 0, 2);
temp32 = CRYPTO_RESP;
rpkt->exten[0] |= htonl(temp32);
sendlen += crypto_xmit(NULL, &xpkt, rbufp,
sendlen, (struct exten *)rpkt->exten,
cookie);
} else {
session_key(&rbufp->dstadr->sin,
&rbufp->recv_srcadr, xkeyid, cookie, 2);
}
}
#endif
get_systime(&xmt_tx);
sendlen += authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen);
#ifdef OPENSSL
if (xkeyid > NTP_MAXKEY)
authtrust(xkeyid, 0);
#endif
sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, &xpkt, sendlen);
get_systime(&xmt_ty);
L_SUB(&xmt_ty, &xmt_tx);
sys_authdelay = xmt_ty;
#ifdef DEBUG
if (debug)
printf(
"transmit: at %ld %s->%s mode %d keyid %08x len %d\n",
current_time, ntoa(&rbufp->dstadr->sin),
ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen);
#endif
}
#ifdef OPENSSL
void
key_expire(
struct peer *peer
)
{
int i;
if (peer->keylist != NULL) {
for (i = 0; i <= peer->keynumber; i++)
authtrust(peer->keylist[i], 0);
free(peer->keylist);
peer->keylist = NULL;
}
value_free(&peer->sndval);
peer->keynumber = 0;
peer->flags &= ~FLAG_ASSOC;
#ifdef DEBUG
if (debug)
printf("key_expire: at %lu associd %d\n", current_time,
peer->associd);
#endif
}
#endif
int
peer_unfit(
struct peer *peer
)
{
int rval = 0;
if (peer->leap == LEAP_NOTINSYNC || peer->stratum < sys_floor ||
peer->stratum >= sys_ceiling)
rval |= TEST10;
if (!(peer->flags & FLAG_REFCLOCK) && root_distance(peer) >=
sys_maxdist + clock_phi * ULOGTOD(peer->hpoll))
rval |= TEST11;
if (peer->stratum > 1 && peer->refid != htonl(LOOPBACKADR) &&
(peer->refid == (peer->dstadr ? peer->dstadr->addr_refid :
0) || peer->refid == sys_refid))
rval |= TEST12;
if (!peer->reach || (peer->flags & FLAG_NOSELECT))
rval |= TEST13;
peer->flash &= ~PEER_TEST_MASK;
peer->flash |= rval;
return (rval);
}
#define MINSTEP 100e-9
#define MAXSTEP 20e-3
#define MINLOOPS 5
int
default_get_precision(void)
{
l_fp val;
l_fp last;
l_fp diff;
double tick;
double dtemp;
int i;
tick = MAXSTEP;
i = 0;
get_systime(&last);
while (1) {
get_systime(&val);
diff = val;
L_SUB(&diff, &last);
last = val;
LFPTOD(&diff, dtemp);
if (dtemp < MINSTEP)
continue;
if (dtemp < tick)
tick = dtemp;
if (++i >= MINLOOPS)
break;
}
sys_tick = tick;
msyslog(LOG_NOTICE, "proto: precision = %.3f usec", tick * 1e6);
for (i = 0; tick <= 1; i++)
tick *= 2;
if (tick - 1 > 1 - tick / 2)
i--;
return (-i);
}
void
init_proto(void)
{
l_fp dummy;
int i;
sys_leap = LEAP_NOTINSYNC;
sys_stratum = STRATUM_UNSPEC;
memcpy(&sys_refid, "INIT", 4);
sys_peer = NULL;
sys_rootdelay = 0;
sys_rootdisp = 0;
L_CLR(&sys_reftime);
sys_jitter = 0;
sys_precision = (s_char)default_get_precision();
get_systime(&dummy);
sys_survivors = 0;
sys_manycastserver = 0;
sys_bclient = 0;
sys_bdelay = 0;
sys_authenticate = 1;
sys_stattime = current_time;
proto_clr_stats();
for (i = 0; i < MAX_TTL; i++) {
sys_ttl[i] = (u_char)((i * 256) / MAX_TTL);
sys_ttlmax = i;
}
pps_enable = 0;
stats_control = 1;
}
void
proto_config(
int item,
u_long value,
double dvalue,
sockaddr_u *svalue
)
{
DPRINTF(2, ("proto_config: code %d value %lu dvalue %lf\n",
item, value, dvalue));
switch (item) {
case PROTO_AUTHENTICATE:
sys_authenticate = value;
break;
case PROTO_BROADCLIENT:
sys_bclient = (int)value;
if (sys_bclient == 0)
io_unsetbclient();
else
io_setbclient();
break;
#ifdef REFCLOCK
case PROTO_CAL:
cal_enable = value;
break;
#endif
case PROTO_KERNEL:
kern_enable = value;
break;
case PROTO_MONITOR:
if (value)
mon_start(MON_ON);
else
mon_stop(MON_ON);
break;
case PROTO_NTP:
ntp_enable = value;
break;
case PROTO_PPS:
pps_enable = value;
break;
case PROTO_FILEGEN:
stats_control = value;
break;
case PROTO_BEACON:
sys_beacon = (int)dvalue;
break;
case PROTO_BROADDELAY:
sys_bdelay = dvalue;
break;
case PROTO_CEILING:
sys_ceiling = (int)dvalue;
break;
case PROTO_COHORT:
sys_cohort = (int)dvalue;
break;
case PROTO_FLOOR:
sys_floor = (int)dvalue;
break;
case PROTO_MAXCLOCK:
sys_maxclock = (int)dvalue;
break;
case PROTO_MAXDIST:
sys_maxdist = dvalue;
break;
case PROTO_CALLDELAY:
break;
case PROTO_MINCLOCK:
sys_minclock = (int)dvalue;
break;
case PROTO_MINDISP:
sys_mindisp = dvalue;
break;
case PROTO_MINSANE:
sys_minsane = (int)dvalue;
break;
case PROTO_ORPHAN:
sys_orphan = (int)dvalue;
break;
case PROTO_ADJ:
sys_tick = dvalue;
break;
case PROTO_MULTICAST_ADD:
if (svalue != NULL)
io_multicast_add(svalue);
sys_bclient = 1;
break;
case PROTO_MULTICAST_DEL:
if (svalue != NULL)
io_multicast_del(svalue);
break;
default:
msyslog(LOG_NOTICE,
"proto: unsupported option %d", item);
}
}
void
proto_clr_stats(void)
{
sys_stattime = current_time;
sys_received = 0;
sys_processed = 0;
sys_newversion = 0;
sys_oldversion = 0;
sys_declined = 0;
sys_restricted = 0;
sys_badlength = 0;
sys_badauth = 0;
sys_limitrejected = 0;
}