#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>
#if defined(VMS) && defined(VMS_LOCALUNIT)
#include "ntp_refclock.h"
#endif
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
#include <sys/sysctl.h>
#endif
u_char sys_leap;
u_char sys_stratum;
s_char sys_precision;
double sys_rootdelay;
double sys_rootdispersion;
u_int32 sys_refid;
u_int32 sys_peer_refid;
static double sys_offset;
l_fp sys_reftime;
struct peer *sys_peer;
struct peer *sys_prefer;
int sys_kod;
int sys_kod_rate = 2;
#ifdef OPENSSL
u_long sys_automax;
#endif
int sys_bclient;
double sys_bdelay;
int sys_calldelay;
int sys_authenticate;
l_fp sys_authdelay;
static u_long sys_authdly[2];
static u_char leap_consensus;
static double sys_selerr;
static double sys_syserr;
keyid_t sys_private;
int sys_manycastserver;
int peer_ntpdate;
int sys_survivors;
#ifdef OPENSSL
char *sys_hostname;
#endif
int sys_floor = 1;
int sys_ceiling = STRATUM_UNSPEC;
int sys_minsane = 1;
int sys_minclock = NTP_MINCLOCK;
int sys_cohort = 0;
int sys_ttlmax;
u_char sys_ttl[MAX_TTL];
u_long sys_stattime;
u_long sys_received;
u_long sys_processed;
u_long sys_newversionpkt;
u_long sys_oldversionpkt;
u_long sys_unknownversion;
u_long sys_restricted;
u_long sys_badlength;
u_long sys_badauth;
u_long sys_limitrejected;
static double root_distance P((struct peer *));
static double clock_combine P((struct peer **, int));
static void peer_xmit P((struct peer *));
static void fast_xmit P((struct recvbuf *, int, keyid_t, int));
static void clock_update P((void));
int default_get_precision P((void));
static int peer_unfit P((struct peer *));
void
transmit(
struct peer *peer
)
{
int hpoll;
hpoll = peer->hpoll;
if (peer->cast_flags & (MDF_BCAST | MDF_MCAST)) {
hpoll = peer->minpoll;
} else if (peer->cast_flags & MDF_ACAST) {
if (sys_survivors < sys_minclock && peer->ttl <
sys_ttlmax)
peer->ttl++;
hpoll = sys_poll;
} else {
peer->unreach++;
if (peer->unreach >= NTP_UNREACH) {
hpoll++;
if (peer->flags & FLAG_CONFIG) {
if (memcmp((char *)&peer->refid,
"DENY", 4) == 0 ||
memcmp((char *)&peer->refid,
"CRYP", 4) == 0)
peer->flash |= TEST4;
} else {
unpeer(peer);
return;
}
}
if (peer->burst == 0) {
u_char oreach;
oreach = peer->reach;
peer->reach <<= 1;
peer->hyst *= HYST_TC;
if (peer->reach == 0) {
if (oreach != 0) {
report_event(EVNT_UNREACH,
peer);
peer->timereachable =
current_time;
if (peer->flags & FLAG_CONFIG) {
peer_clear(peer,
"INIT");
} else {
unpeer(peer);
return;
}
}
if (peer->flags & FLAG_IBURST)
peer->burst = NTP_BURST;
} else {
if (!(peer->reach & 0x07)) {
clock_filter(peer, 0., 0.,
MAXDISPERSE);
clock_select();
}
if (peer_unfit(peer))
hpoll++;
else
hpoll = sys_poll;
if (peer->flags & FLAG_BURST)
peer->burst = NTP_BURST;
}
} else {
if (memcmp((char *)&peer->refid, "RSTR", 4) ==
0)
peer->burst = 0;
else
peer->burst--;
if (peer->burst == 0) {
if (peer->cast_flags & MDF_BCLNT) {
peer->hmode = MODE_BCLIENT;
#ifdef OPENSSL
key_expire(peer);
#endif
}
poll_update(peer, hpoll);
clock_select();
if (mode_ntpdate) {
peer_ntpdate--;
if (peer_ntpdate > 0) {
poll_update(
peer, hpoll);
return;
}
msyslog(LOG_NOTICE,
"no reply; clock not set");
exit (0);
}
poll_update(peer, hpoll);
return;
}
}
}
peer->outdate = current_time;
if (peer->hmode == MODE_BCLIENT || peer->flash & TEST4) {
poll_update(peer, hpoll);
return;
} else if (peer->hmode == MODE_BROADCAST && sys_peer == NULL) {
poll_update(peer, hpoll);
return;
}
peer_xmit(peer);
poll_update(peer, hpoll);
}
void
receive(
struct recvbuf *rbufp
)
{
register struct peer *peer;
register struct pkt *pkt;
int hismode;
int restrict_mask;
int has_mac;
int authlen;
int is_authentic;
keyid_t skeyid = 0;
struct sockaddr_storage *dstadr_sin;
struct peer *peer2;
l_fp p_org;
l_fp p_xmt;
#ifdef OPENSSL
keyid_t tkeyid = 0;
keyid_t pkeyid = 0;
struct autokey *ap;
int rval;
#endif
int retcode = AM_NOMATCH;
sys_received++;
if (SRCPORT(&rbufp->recv_srcadr) == 0) {
sys_badlength++;
return;
}
ntp_monitor(rbufp);
restrict_mask = restrictions(&rbufp->recv_srcadr);
#ifdef DEBUG
if (debug > 1)
printf("receive: at %ld %s<-%s restrict %03x\n",
current_time, stoa(&rbufp->dstadr->sin),
stoa(&rbufp->recv_srcadr), restrict_mask);
#endif
if (restrict_mask & RES_IGNORE) {
sys_restricted++;
return;
}
pkt = &rbufp->recv_pkt;
hismode = (int)PKT_MODE(pkt->li_vn_mode);
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 (rbufp->recv_length < LEN_PKT_NOMAC) {
sys_badlength++;
return;
}
if (PKT_VERSION(pkt->li_vn_mode) == NTP_VERSION) {
sys_newversionpkt++;
} else if (!(restrict_mask & RES_VERSION) &&
PKT_VERSION(pkt->li_vn_mode) >= NTP_OLDVERSION) {
sys_oldversionpkt++;
} else {
sys_unknownversion++;
return;
}
if (hismode == MODE_UNSPEC) {
if (PKT_VERSION(pkt->li_vn_mode) == NTP_OLDVERSION) {
hismode = MODE_CLIENT;
} else {
sys_badlength++;
return;
}
}
if (hismode == MODE_BROADCAST) {
if (!sys_bclient || restrict_mask & RES_NOPEER) {
sys_restricted++;
return;
}
#ifdef OPENSSL
if (crypto_flags && rbufp->dstadr == any_interface) {
sys_restricted++;
return;
}
#endif
}
authlen = LEN_PKT_NOMAC;
has_mac = rbufp->recv_length - authlen;
while (has_mac > 0) {
int temp;
if (has_mac % 4 != 0 || has_mac < 0) {
sys_badlength++;
return;
}
if (has_mac == 1 * 4 || has_mac == 3 * 4 || has_mac ==
MAX_MAC_LEN) {
skeyid = ntohl(((u_int32 *)pkt)[authlen / 4]);
break;
} else if (has_mac > MAX_MAC_LEN) {
temp = ntohl(((u_int32 *)pkt)[authlen / 4]) &
0xffff;
if (temp < 4 || temp > NTP_MAXEXTEN || temp % 4
!= 0) {
sys_badlength++;
return;
}
authlen += temp;
has_mac -= temp;
} else {
sys_badlength++;
return;
}
}
#ifdef OPENSSL
pkeyid = tkeyid = 0;
#endif
peer = findpeer(&rbufp->recv_srcadr, rbufp->dstadr, rbufp->fd,
hismode, &retcode);
is_authentic = 0;
dstadr_sin = &rbufp->dstadr->sin;
if (has_mac == 0) {
#ifdef DEBUG
if (debug)
printf("receive: at %ld %s<-%s mode %d code %d\n",
current_time, stoa(&rbufp->dstadr->sin),
stoa(&rbufp->recv_srcadr), hismode,
retcode);
#endif
} else {
#ifdef OPENSSL
if (skeyid > NTP_MAXKEY) {
if (hismode == MODE_BROADCAST) {
pkeyid = 0;
if (!SOCKNUL(&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 = 1;
restrict_mask &= ~RES_DONTTRUST;
} else {
sys_badauth++;
}
#ifdef OPENSSL
if (skeyid > NTP_MAXKEY)
authtrust(skeyid, 0);
#endif
#ifdef DEBUG
if (debug)
printf(
"receive: at %ld %s<-%s mode %d code %d keyid %08x len %d mac %d auth %d\n",
current_time, stoa(dstadr_sin),
stoa(&rbufp->recv_srcadr), hismode, retcode,
skeyid, authlen, has_mac,
is_authentic);
#endif
}
switch (retcode) {
case AM_FXMIT:
if (sys_manycastserver && (rbufp->dstadr->flags &
INT_MULTICAST)) {
if (sys_peer == NULL ||
PKT_TO_STRATUM(pkt->stratum) <
sys_stratum || (sys_cohort &&
PKT_TO_STRATUM(pkt->stratum) ==
sys_stratum) ||
rbufp->dstadr->addr_refid == pkt->refid)
return;
}
if (has_mac && !is_authentic)
fast_xmit(rbufp, MODE_SERVER, 0, restrict_mask);
else
fast_xmit(rbufp, MODE_SERVER, skeyid,
restrict_mask);
return;
case AM_MANYCAST:
if (restrict_mask & RES_DONTTRUST) {
sys_restricted++;
return;
}
if (sys_authenticate && !is_authentic)
return;
if ((peer2 = findmanycastpeer(rbufp)) == NULL)
return;
if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr,
MODE_CLIENT, PKT_VERSION(pkt->li_vn_mode),
NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_IBURST, MDF_UCAST |
MDF_ACLNT, 0, skeyid)) == NULL)
return;
peer->ttl = peer2->ttl;
break;
case AM_NEWPASS:
if (restrict_mask & RES_DONTTRUST) {
sys_restricted++;
return;
}
if (sys_authenticate && !is_authentic) {
fast_xmit(rbufp, MODE_PASSIVE, 0,
restrict_mask);
return;
}
if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr,
MODE_PASSIVE, PKT_VERSION(pkt->li_vn_mode),
NTP_MINDPOLL, NTP_MAXDPOLL, 0, MDF_UCAST, 0,
skeyid)) == NULL)
return;
break;
case AM_NEWBCL:
if (restrict_mask & RES_DONTTRUST) {
sys_restricted++;
return;
}
if (sys_authenticate && !is_authentic)
return;
if (!sys_bclient)
return;
if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr,
MODE_CLIENT, PKT_VERSION(pkt->li_vn_mode),
NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_MCAST |
FLAG_IBURST, MDF_BCLNT, 0, skeyid)) == NULL)
return;
#ifdef OPENSSL
if (crypto_flags) {
if ((rval = crypto_recv(peer, rbufp)) !=
XEVNT_OK) {
struct sockaddr_storage mskadr_sin;
unpeer(peer);
sys_restricted++;
SET_HOSTMASK(&mskadr_sin,
rbufp->recv_srcadr.ss_family);
hack_restrict(RESTRICT_FLAGS,
&rbufp->recv_srcadr, &mskadr_sin,
0, RES_DONTTRUST | RES_TIMEOUT);
#ifdef DEBUG
if (debug)
printf(
"packet: bad exten %x\n",
rval);
#endif
}
}
#endif
return;
case AM_POSSBCL:
case AM_PROCPKT:
peer->flash = 0;
if (restrict_mask & RES_DONTTRUST) {
sys_restricted++;
if (peer->flags & FLAG_CONFIG)
peer_clear(peer, "RSTR");
else
unpeer(peer);
return;
}
if (has_mac && !is_authentic)
peer->flash |= TEST5;
break;
default:
if (has_mac && hismode == MODE_PASSIVE)
fast_xmit(rbufp, MODE_ACTIVE, 0, restrict_mask);
#ifdef DEBUG
if (debug)
printf("receive: bad protocol %d\n", retcode);
#endif
return;
}
peer->timereceived = current_time;
peer->received++;
if (peer->flash & TEST5)
peer->flags &= ~FLAG_AUTHENTIC;
else
peer->flags |= FLAG_AUTHENTIC;
NTOHL_FP(&pkt->org, &p_org);
NTOHL_FP(&pkt->xmt, &p_xmt);
if (L_ISEQU(&peer->org, &p_xmt)) {
peer->flash |= TEST1;
} else if (hismode == MODE_BROADCAST) {
if (peer->flash & TEST5) {
unpeer(peer);
return;
}
} else if (L_ISEQU(&peer->xmt, &p_org)) {
if (peer->flash & TEST5) {
if (has_mac == 4 && pkt->exten[0] == 0) {
if (peer->flags & FLAG_CONFIG)
peer_clear(peer, "AUTH");
else
unpeer(peer);
}
return;
}
} else if (L_ISZERO(&peer->xmt)) {
} else if (!L_ISZERO(&p_org)) {
if (peer->cast_flags & MDF_ACLNT)
return;
peer->flash |= TEST2;
} else if (L_ISZERO(&peer->org)) {
} else {
if (hismode == MODE_ACTIVE)
fast_xmit(rbufp, MODE_PASSIVE, 0,
restrict_mask);
else if (hismode == MODE_PASSIVE)
fast_xmit(rbufp, MODE_ACTIVE, 0, restrict_mask);
#if DEBUG
if (debug)
printf("receive: dropped %03x\n", peer->flash);
#endif
if (peer->flags & FLAG_CONFIG)
peer_clear(peer, "DROP");
else
unpeer(peer);
return;
}
if (peer->flash & ~TEST2) {
return;
}
#ifdef OPENSSL
if (crypto_flags && (peer->flags & FLAG_SKEY)) {
peer->flash |= TEST10;
rval = crypto_recv(peer, rbufp);
if (rval != XEVNT_OK) {
} else if (hismode == MODE_SERVER) {
if (skeyid == peer->keyid)
peer->flash &= ~TEST10;
} else if (!peer->flash & TEST10) {
peer->pkeyid = skeyid;
} else if ((ap = (struct autokey *)peer->recval.ptr) !=
NULL) {
int i;
for (i = 0; ; i++) {
if (tkeyid == peer->pkeyid ||
tkeyid == ap->key) {
peer->flash &= ~TEST10;
peer->pkeyid = skeyid;
break;
}
if (i > ap->seq)
break;
tkeyid = session_key(
&rbufp->recv_srcadr, dstadr_sin,
tkeyid, pkeyid, 0);
}
}
if (!(peer->crypto & CRYPTO_FLAG_PROV))
peer->flash |= TEST11;
if (peer->cmmd != 0) {
peer->ppoll = pkt->ppoll;
poll_update(peer, 0);
}
if (rval != XEVNT_OK) {
if (peer->flags & FLAG_CONFIG)
peer_clear(peer, "CRYP");
else
unpeer(peer);
#ifdef DEBUG
if (debug)
printf("packet: bad exten %x\n", rval);
#endif
return;
}
if (peer->flash & TEST10 && peer->crypto &
CRYPTO_FLAG_AUTO) {
poll_update(peer, peer->minpoll);
#ifdef DEBUG
if (debug)
printf(
"packet: bad auto %03x\n",
peer->flash);
#endif
if (peer->flags & FLAG_CONFIG)
peer_clear(peer, "AUTO");
else
unpeer(peer);
return;
}
}
#endif
process_packet(peer, pkt, &rbufp->recv_time);
}
void
process_packet(
register struct peer *peer,
register struct pkt *pkt,
l_fp *recv_ts
)
{
l_fp t34, t21;
double p_offset, p_del, p_disp;
double dtemp;
l_fp p_rec, p_xmt, p_org, p_reftime;
l_fp ci;
u_char pmode, pleap, pstratum;
sys_processed++;
peer->processed++;
p_del = FPTOD(NTOHS_FP(pkt->rootdelay));
p_disp = FPTOD(NTOHS_FP(pkt->rootdispersion));
NTOHL_FP(&pkt->reftime, &p_reftime);
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);
if (pmode != MODE_BROADCAST)
NTOHL_FP(&pkt->org, &p_org);
else
p_org = peer->rec;
pstratum = PKT_TO_STRATUM(pkt->stratum);
if (L_ISHIS(&peer->org, &p_xmt))
peer->oldpkt++;
if (pmode != MODE_BROADCAST && (L_ISZERO(&p_rec) ||
L_ISZERO(&p_org)))
peer->flash |= TEST3;
if (L_ISZERO(&p_xmt))
peer->flash |= TEST3;
peer->org = p_xmt;
peer->rec = *recv_ts;
if (peer->flash) {
#ifdef DEBUG
if (debug)
printf("packet: bad data %03x from address: %s\n",
peer->flash, stoa(&peer->srcadr));
#endif
return;
}
peer->leap = pleap;
peer->stratum = pstratum;
peer->refid = pkt->refid;
ci = p_xmt;
L_SUB(&ci, &p_reftime);
LFPTOD(&ci, dtemp);
if (pleap == LEAP_NOTINSYNC ||
pstratum >= STRATUM_UNSPEC || dtemp < 0)
peer->flash |= TEST6;
if (!(peer->flags & FLAG_CONFIG) && sys_peer != NULL) {
if (pstratum > sys_stratum && pmode != MODE_ACTIVE)
peer->flash |= TEST7;
}
if (p_del < 0 || p_disp < 0 || p_del /
2 + p_disp >= MAXDISPERSE)
peer->flash |= TEST8;
if (peer->flash) {
#ifdef DEBUG
if (debug)
printf("packet: bad header %03x\n",
peer->flash);
#endif
return;
}
record_raw_stats(&peer->srcadr, &peer->dstadr->sin, &p_org,
&p_rec, &p_xmt, &peer->rec);
peer->pmode = pmode;
peer->ppoll = pkt->ppoll;
peer->precision = pkt->precision;
peer->rootdelay = p_del;
peer->rootdispersion = p_disp;
peer->reftime = p_reftime;
if (!(peer->reach)) {
report_event(EVNT_REACH, peer);
peer->timereachable = current_time;
}
peer->reach |= 1;
peer->unreach = 0;
poll_update(peer, 0);
t34 = p_xmt;
L_SUB(&t34, &peer->rec);
t21 = p_rec;
L_SUB(&t21, &p_org);
ci = peer->rec;
L_SUB(&ci, &p_org);
LFPTOD(&ci, p_disp);
p_disp = clock_phi * max(p_disp, LOGTOD(sys_precision));
ci = t34;
if (pmode == MODE_BROADCAST) {
if (peer->flags & FLAG_MCAST) {
LFPTOD(&ci, p_offset);
peer->estbdelay = peer->offset - p_offset;
if (peer->hmode == MODE_CLIENT)
return;
peer->flags &= ~FLAG_MCAST;
}
DTOLFP(peer->estbdelay, &t34);
L_ADD(&ci, &t34);
p_del = peer->delay;
} else {
L_ADD(&ci, &t21);
L_RSHIFT(&ci);
L_SUB(&t21, &t34);
LFPTOD(&t21, p_del);
}
p_del = max(p_del, LOGTOD(sys_precision));
LFPTOD(&ci, p_offset);
if ((peer->rootdelay + p_del) / 2. + peer->rootdispersion +
p_disp >= MAXDISPERSE)
peer->flash |= TEST9;
if (peer->flash) {
#ifdef DEBUG
if (debug)
printf("packet: bad packet data %03x\n",
peer->flash);
#endif
return;
}
clock_filter(peer, p_offset, p_del, p_disp);
clock_select();
record_peer_stats(&peer->srcadr, ctlpeerstatus(peer),
peer->offset, peer->delay, peer->disp,
SQRT(peer->jitter));
}
static void
clock_update(void)
{
u_char oleap;
u_char ostratum;
if (sys_peer == NULL)
return;
if (sys_peer->epoch <= last_time)
return;
#ifdef DEBUG
if (debug)
printf("clock_update: at %ld assoc %d \n", current_time,
peer_associations);
#endif
oleap = sys_leap;
ostratum = sys_stratum;
switch (local_clock(sys_peer, sys_offset, sys_syserr)) {
case -1:
report_event(EVNT_SYSFAULT, NULL);
exit (-1);
case 1:
clear_all();
sys_peer = NULL;
sys_stratum = STRATUM_UNSPEC;
memcpy(&sys_refid, "STEP", 4);
sys_poll = NTP_MINPOLL;
report_event(EVNT_CLOCKRESET, NULL);
#ifdef OPENSSL
if (oleap != LEAP_NOTINSYNC)
expire_all();
#endif
break;
default:
sys_stratum = (u_char) (sys_peer->stratum + 1);
if (sys_stratum == 1 || sys_stratum == STRATUM_UNSPEC)
sys_refid = sys_peer->refid;
else
sys_refid = sys_peer_refid;
sys_reftime = sys_peer->rec;
sys_rootdelay = sys_peer->rootdelay + sys_peer->delay;
sys_leap = leap_consensus;
if (oleap == LEAP_NOTINSYNC) {
report_event(EVNT_SYNCCHG, NULL);
#ifdef OPENSSL
expire_all();
#endif
}
}
if (ostratum != sys_stratum)
report_event(EVNT_PEERSTCHG, NULL);
}
void
poll_update(
struct peer *peer,
int hpoll
)
{
#ifdef OPENSSL
int oldpoll;
#endif
#ifdef OPENSSL
oldpoll = peer->kpoll;
#endif
if (hpoll > 0) {
if (hpoll > peer->maxpoll)
peer->hpoll = peer->maxpoll;
else if (hpoll < peer->minpoll)
peer->hpoll = peer->minpoll;
else
peer->hpoll = (u_char)hpoll;
}
#ifdef OPENSSL
if (peer->cmmd != NULL && (sys_leap != LEAP_NOTINSYNC ||
peer->crypto)) {
peer->nextdate = current_time + RESP_DELAY;
} else if (peer->burst > 0) {
#else
if (peer->burst > 0) {
#endif
if (hpoll == 0 && peer->nextdate != current_time)
return;
#ifdef REFCLOCK
else if (peer->flags & FLAG_REFCLOCK)
peer->nextdate += RESP_DELAY;
#endif
else if (peer->flags & (FLAG_IBURST | FLAG_BURST) &&
peer->burst == NTP_BURST)
peer->nextdate += sys_calldelay;
else
peer->nextdate += BURST_DELAY;
} else if (peer->cast_flags & MDF_ACAST) {
if (sys_survivors >= sys_minclock || peer->ttl >=
sys_ttlmax)
peer->kpoll = (u_char) (peer->hpoll + 3);
else
peer->kpoll = peer->hpoll;
peer->nextdate = peer->outdate + RANDPOLL(peer->kpoll);
} else {
peer->kpoll = (u_char) max(min(peer->ppoll,
peer->hpoll), peer->minpoll);
peer->nextdate = peer->outdate + RANDPOLL(peer->kpoll);
}
if (peer->nextdate < current_time)
peer->nextdate = current_time;
#ifdef OPENSSL
if (peer->kpoll != oldpoll)
key_expire(peer);
#endif
#ifdef DEBUG
if (debug > 1)
printf("poll_update: at %lu %s flags %04x poll %d burst %d last %lu next %lu\n",
current_time, ntoa(&peer->srcadr), peer->flags,
peer->kpoll, peer->burst, peer->outdate,
peer->nextdate);
#endif
}
void
peer_clear(
struct peer *peer,
char *ident
)
{
u_char oreach, i;
oreach = peer->reach;
#ifdef OPENSSL
key_expire(peer);
if (peer->pkey != NULL)
EVP_PKEY_free(peer->pkey);
if (peer->ident_pkey != NULL)
EVP_PKEY_free(peer->ident_pkey);
if (peer->subject != NULL)
free(peer->subject);
if (peer->issuer != NULL)
free(peer->issuer);
if (peer->iffval != NULL)
BN_free(peer->iffval);
if (peer->grpkey != NULL)
BN_free(peer->grpkey);
if (peer->cmmd != NULL)
free(peer->cmmd);
value_free(&peer->cookval);
value_free(&peer->recval);
value_free(&peer->tai_leap);
value_free(&peer->encrypt);
value_free(&peer->sndval);
#endif
memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO);
if (peer == sys_peer)
sys_peer = NULL;
peer->estbdelay = sys_bdelay;
peer->hpoll = peer->kpoll = peer->minpoll;
peer->ppoll = peer->maxpoll;
peer->jitter = MAXDISPERSE;
peer->epoch = current_time;
#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
for (i = 0; i < NTP_SHIFT; i++) {
peer->filter_order[i] = i;
peer->filter_disp[i] = MAXDISPERSE;
peer->filter_epoch[i] = current_time;
}
if (peer->cast_flags & MDF_BCLNT) {
peer->flags |= FLAG_MCAST;
peer->hmode = MODE_CLIENT;
}
peer->nextdate = peer->update = peer->outdate = current_time;
peer->burst = 0;
if (oreach)
poll_update(peer, 0);
else if (initializing)
peer->nextdate = current_time + peer_associations;
else
peer->nextdate = current_time + (u_int)RANDOM %
peer_associations;
#ifdef DEBUG
if (debug)
printf("peer_clear: at %ld assoc ID %d refid %s\n",
current_time, 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 dsp, jit, dtemp, etemp;
dsp = min(LOGTOD(peer->precision) + LOGTOD(sys_precision) +
sample_disp, MAXDISPERSE);
j = peer->filter_nextpt;
peer->filter_offset[j] = sample_offset;
peer->filter_delay[j] = max(0, sample_delay);
peer->filter_disp[j] = dsp;
j++; j %= NTP_SHIFT;
peer->filter_nextpt = (u_short) 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;
if (peer->filter_disp[j] >= MAXDISPERSE)
dst[i] = MAXDISPERSE;
else if (peer->update - peer->filter_epoch[j] >
allan_xpt)
dst[i] = MAXDISTANCE + peer->filter_disp[j];
else
dst[i] = peer->filter_delay[j];
ord[i] = j;
j++; j %= NTP_SHIFT;
}
peer->filter_epoch[j] = current_time;
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] >=
MAXDISTANCE))
continue;
m++;
}
jit = 0;
peer->disp = 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)
jit += DIFF(peer->filter_offset[j],
peer->filter_offset[k]);
}
if (m == 0)
return;
etemp = fabs(peer->offset - peer->filter_offset[k]);
dtemp = sqrt(peer->jitter);
peer->offset = peer->filter_offset[k];
peer->delay = peer->filter_delay[k];
if (m > 1)
jit /= m - 1;
peer->jitter = max(jit, SQUARE(LOGTOD(sys_precision)));
if (peer->filter_epoch[k] <= peer->epoch && sys_leap !=
LEAP_NOTINSYNC) {
#ifdef DEBUG
if (debug)
printf("clock_filter: discard %lu\n",
peer->epoch - peer->filter_epoch[k]);
#endif
return;
}
if (m > 1 && etemp > CLOCK_SGATE * dtemp &&
(long)(peer->filter_epoch[k] - peer->epoch) < (1 << (sys_poll +
1))) {
#ifdef DEBUG
if (debug)
printf("clock_filter: popcorn %.6f %.6f\n",
etemp, dtemp);
#endif
return;
}
peer->epoch = peer->filter_epoch[k];
#ifdef DEBUG
if (debug)
printf(
"clock_filter: n %d off %.6f del %.6f dsp %.6f jit %.6f, age %lu\n",
m, peer->offset, peer->delay, peer->disp,
SQRT(peer->jitter), peer->update - peer->epoch);
#endif
}
void
clock_select(void)
{
struct peer *peer;
int i, j, k, n;
int nlist, nl3;
double d, e, f;
int allow, sw, osurv;
double high, low;
double synch[NTP_MAXCLOCK], error[NTP_MAXCLOCK];
struct peer *osys_peer;
struct peer *typeacts = NULL;
struct peer *typelocal = NULL;
struct peer *typepps = NULL;
struct peer *typesystem = NULL;
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;
sys_peer = NULL;
osurv = sys_survivors;
sys_survivors = 0;
sys_prefer = NULL;
#ifdef LOCKCLOCK
sys_leap = LEAP_NOTINSYNC;
sys_stratum = STRATUM_UNSPEC;
memcpy(&sys_refid, "DOWN", 4);
#endif
nlist = 0;
for (n = 0; n < 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 = emalloc(endpoint_size);
indx = emalloc(indx_size);
peer_list = emalloc(peer_list_size);
}
nlist = nl3 = 0;
for (n = 0; n < 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->refclktype == REFCLK_LOCALCLOCK
#if defined(VMS) && defined(VMS_LOCALUNIT)
&& REFCLOCKUNIT(&peer->srcadr) !=
VMS_LOCALUNIT
#endif
) {
typelocal = peer;
if (!(peer->flags & FLAG_PREFER))
continue;
#ifdef LOCKCLOCK
else
sys_prefer = peer;
#endif
}
if (peer->sstclktype == CTL_SST_TS_TELEPHONE) {
typeacts = peer;
if (!(peer->flags & FLAG_PREFER))
continue;
}
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;
}
if (high <= low) {
if (typeacts != 0) {
typeacts->status = CTL_PST_SEL_SANE;
peer_list[0] = typeacts;
nlist = 1;
} else if (typelocal != 0) {
typelocal->status = CTL_PST_SEL_SANE;
peer_list[0] = typelocal;
nlist = 1;
} else {
if (osys_peer != NULL) {
sys_poll = NTP_MINPOLL;
NLOG(NLOG_SYNCSTATUS)
msyslog(LOG_INFO,
"no servers reachable");
report_event(EVNT_PEERSTCHG, NULL);
}
if (osurv > 0)
resetmanycast();
return;
}
}
if (nlist < sys_minsane)
return;
j = 0;
for (i = 0; i < nlist; i++) {
peer = peer_list[i];
if (nlist > 1 && (peer->offset <= low || peer->offset >=
high)) {
if (!(peer->flags & FLAG_CONFIG))
unpeer(peer);
continue;
}
peer->status = CTL_PST_SEL_DISTSYSPEER;
d = peer->stratum;
if (d < sys_floor)
d += sys_floor;
if (d > sys_ceiling)
d = STRATUM_UNSPEC;
d = root_distance(peer) + d * MAXDISTANCE;
d *= 1. - peer->hyst;
if (j >= NTP_MAXCLOCK) {
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) {
#ifdef DEBUG
if (debug)
printf("clock_select: empty intersection interval\n");
#endif
return;
}
for (i = 0; i < nlist; i++) {
peer_list[i]->status = CTL_PST_SEL_SELCAND;
#ifdef DEBUG
if (debug > 2)
printf("select: %s distance %.6f jitter %.6f\n",
ntoa(&peer_list[i]->srcadr), synch[i],
SQRT(error[i]));
#endif
}
while (1) {
d = 1e9;
e = -1e9;
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 /= nlist - 1;
}
if (f * synch[i] > e) {
sys_selerr = f;
e = f * synch[i];
k = i;
}
}
f = max(sys_selerr, SQUARE(LOGTOD(sys_precision)));
if (nlist <= sys_minclock || f <= d ||
peer_list[k]->flags & FLAG_PREFER)
break;
#ifdef DEBUG
if (debug > 2)
printf(
"select: drop %s select %.6f jitter %.6f\n",
ntoa(&peer_list[k]->srcadr),
SQRT(sys_selerr), SQRT(d));
#endif
if (!(peer_list[k]->flags & FLAG_CONFIG) &&
peer_list[k]->hmode == MODE_CLIENT)
unpeer(peer_list[k]);
for (j = k + 1; j < nlist; j++) {
peer_list[j - 1] = peer_list[j];
error[j - 1] = error[j];
}
nlist--;
}
leap_consensus = 0;
for (i = nlist - 1; i >= 0; i--) {
peer = peer_list[i];
leap_consensus |= peer->leap;
peer->status = CTL_PST_SEL_SYNCCAND;
peer->rank++;
peer->flags |= FLAG_SYSPEER;
if (peer->stratum >= sys_floor && osurv >= sys_minclock)
peer->hyst = HYST;
else
peer->hyst = 0;
if (peer->stratum <= sys_ceiling)
sys_survivors++;
if (peer->flags & FLAG_PREFER)
sys_prefer = peer;
if (peer->refclktype == REFCLK_ATOM_PPS &&
peer->stratum < STRATUM_UNSPEC)
typepps = peer;
if (peer->stratum == peer_list[0]->stratum && peer ==
osys_peer)
typesystem = peer;
}
if (sys_survivors < sys_minclock && osurv >= sys_minclock)
resetmanycast();
if (sys_prefer)
sw = sys_prefer->refclktype == REFCLK_LOCALCLOCK ||
sys_prefer->sstclktype == CTL_SST_TS_TELEPHONE ||
!typepps;
else
sw = 0;
if (sw) {
sys_peer = sys_prefer;
sys_peer->status = CTL_PST_SEL_SYSPEER;
sys_offset = sys_peer->offset;
sys_syserr = sys_peer->jitter;
#ifdef DEBUG
if (debug > 1)
printf("select: prefer offset %.6f\n",
sys_offset);
#endif
}
#ifndef LOCKCLOCK
else if (typepps) {
sys_peer = typepps;
sys_peer->status = CTL_PST_SEL_PPS;
sys_offset = sys_peer->offset;
sys_syserr = sys_peer->jitter;
if (!pps_control)
NLOG(NLOG_SYSEVENT)
msyslog(LOG_INFO, "pps sync enabled");
pps_control = current_time;
#ifdef DEBUG
if (debug > 1)
printf("select: pps offset %.6f\n",
sys_offset);
#endif
} else {
if (typesystem)
sys_peer = osys_peer;
else
sys_peer = peer_list[0];
sys_peer->status = CTL_PST_SEL_SYSPEER;
sys_peer->rank++;
sys_offset = clock_combine(peer_list, nlist);
sys_syserr = sys_peer->jitter + sys_selerr;
#ifdef DEBUG
if (debug > 1)
printf("select: combine offset %.6f\n",
sys_offset);
#endif
}
#endif
if (osys_peer != sys_peer) {
char *src;
if (sys_peer == NULL)
sys_peer_refid = 0;
else
sys_peer_refid = addr2refid(&sys_peer->srcadr);
report_event(EVNT_PEERSTCHG, NULL);
#ifdef REFCLOCK
if (ISREFCLOCKADR(&sys_peer->srcadr))
src = refnumtoa(&sys_peer->srcadr);
else
#endif
src = ntoa(&sys_peer->srcadr);
NLOG(NLOG_SYNCSTATUS)
msyslog(LOG_INFO, "synchronized to %s, stratum=%d", src,
sys_peer->stratum);
}
clock_update();
}
static double
clock_combine(
struct peer **peers,
int npeers
)
{
int i;
double x, y, z;
y = z = 0;
for (i = 0; i < npeers; i++) {
x = root_distance(peers[i]);
y += 1. / x;
z += peers[i]->offset / x;
}
return (z / y);
}
static double
root_distance(
struct peer *peer
)
{
return ((peer->rootdelay + peer->delay) / 2 +
peer->rootdispersion + peer->disp + clock_phi *
(current_time - peer->update) + SQRT(peer->jitter));
}
static void
peer_xmit(
struct peer *peer
)
{
struct pkt xpkt;
int sendlen, authlen;
keyid_t xkeyid = 0;
l_fp xmt_tx;
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));
xpkt.rootdispersion = HTONS_FP(DTOUFP(sys_rootdispersion));
xpkt.refid = sys_refid;
HTONL_FP(&sys_reftime, &xpkt.reftime);
HTONL_FP(&peer->org, &xpkt.org);
HTONL_FP(&peer->rec, &xpkt.rec);
sendlen = LEN_PKT_NOMAC;
if (!(peer->flags & FLAG_AUTHENABLE)) {
get_systime(&peer->xmt);
HTONL_FP(&peer->xmt, &xpkt.xmt);
sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl],
&xpkt, sendlen);
peer->sent++;
#ifdef DEBUG
if (debug)
printf("transmit: at %ld %s->%s mode %d\n",
current_time, stoa(&peer->dstadr->sin),
stoa(&peer->srcadr), peer->hmode);
#endif
return;
}
#ifdef OPENSSL
if (crypto_flags && (peer->flags & FLAG_SKEY)) {
struct exten *exten;
u_int opcode;
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;
switch (peer->hmode) {
case MODE_BROADCAST:
if (peer->flags & FLAG_ASSOC)
exten = crypto_args(peer, CRYPTO_AUTO |
CRYPTO_RESP, NULL);
else
exten = crypto_args(peer, CRYPTO_ASSOC |
CRYPTO_RESP, NULL);
sendlen += crypto_xmit(&xpkt, &peer->srcadr,
sendlen, exten, 0);
free(exten);
break;
case MODE_ACTIVE:
case MODE_PASSIVE:
if (peer->cmmd != NULL) {
peer->cmmd->associd =
htonl(peer->associd);
sendlen += crypto_xmit(&xpkt,
&peer->srcadr, sendlen, peer->cmmd,
0);
free(peer->cmmd);
peer->cmmd = NULL;
}
exten = NULL;
if (!peer->crypto)
exten = crypto_args(peer, CRYPTO_ASSOC,
sys_hostname);
else if (!(peer->crypto & CRYPTO_FLAG_VALID))
exten = crypto_args(peer, CRYPTO_CERT,
peer->issuer);
else if ((opcode = crypto_ident(peer)) != 0)
exten = crypto_args(peer, opcode, NULL);
else if (sys_leap != LEAP_NOTINSYNC &&
!(peer->crypto & CRYPTO_FLAG_SIGN))
exten = crypto_args(peer, CRYPTO_SIGN,
sys_hostname);
else if (sys_leap != LEAP_NOTINSYNC &&
peer->leap != LEAP_NOTINSYNC &&
!(peer->crypto & CRYPTO_FLAG_AGREE))
exten = crypto_args(peer, CRYPTO_COOK,
NULL);
else if (peer->flags & FLAG_ASSOC)
exten = crypto_args(peer, CRYPTO_AUTO |
CRYPTO_RESP, NULL);
else if (!(peer->crypto & CRYPTO_FLAG_AUTO))
exten = crypto_args(peer, CRYPTO_AUTO,
NULL);
else if (sys_leap != LEAP_NOTINSYNC &&
peer->leap != LEAP_NOTINSYNC &&
peer->crypto & CRYPTO_FLAG_TAI &&
!(peer->crypto & CRYPTO_FLAG_LEAP))
exten = crypto_args(peer, CRYPTO_TAI,
NULL);
if (exten != NULL) {
sendlen += crypto_xmit(&xpkt,
&peer->srcadr, sendlen, exten, 0);
free(exten);
}
break;
case MODE_CLIENT:
if (peer->cmmd != NULL) {
peer->cmmd->associd =
htonl(peer->associd);
sendlen += crypto_xmit(&xpkt,
&peer->srcadr, sendlen, peer->cmmd,
0);
free(peer->cmmd);
peer->cmmd = NULL;
}
exten = NULL;
if (!peer->crypto)
exten = crypto_args(peer, CRYPTO_ASSOC,
sys_hostname);
else if (!(peer->crypto & CRYPTO_FLAG_VALID))
exten = crypto_args(peer, CRYPTO_CERT,
peer->issuer);
else if ((opcode = crypto_ident(peer)) != 0)
exten = crypto_args(peer, opcode, NULL);
else if (!(peer->crypto & CRYPTO_FLAG_AGREE))
exten = crypto_args(peer, CRYPTO_COOK,
NULL);
else if (!(peer->crypto & CRYPTO_FLAG_AUTO) &&
(peer->cast_flags & MDF_BCLNT))
exten = crypto_args(peer, CRYPTO_AUTO,
NULL);
else if (sys_leap != LEAP_NOTINSYNC &&
!(peer->crypto & CRYPTO_FLAG_SIGN))
exten = crypto_args(peer, CRYPTO_SIGN,
sys_hostname);
else if (sys_leap != LEAP_NOTINSYNC &&
peer->crypto & CRYPTO_FLAG_TAI &&
!(peer->crypto & CRYPTO_FLAG_LEAP))
exten = crypto_args(peer, CRYPTO_TAI,
NULL);
if (exten != NULL) {
sendlen += crypto_xmit(&xpkt,
&peer->srcadr, sendlen, exten, 0);
free(exten);
}
break;
}
if (sendlen > LEN_PKT_NOMAC)
session_key(&peer->dstadr->sin, &peer->srcadr,
xkeyid, 0, 2);
}
#endif
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) {
msyslog(LOG_INFO,
"transmit: encryption key %d not found", xkeyid);
if (peer->flags & FLAG_CONFIG)
peer_clear(peer, "NKEY");
else
unpeer(peer);
return;
}
sendlen += authlen;
#ifdef OPENSSL
if (xkeyid > NTP_MAXKEY)
authtrust(xkeyid, 0);
#endif
get_systime(&xmt_tx);
if (sendlen > sizeof(xpkt)) {
msyslog(LOG_ERR, "buffer overflow %u", sendlen);
exit (-1);
}
sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl], &xpkt,
sendlen);
L_SUB(&xmt_tx, &peer->xmt);
L_ADD(&xmt_tx, &sys_authdelay);
sys_authdly[1] = sys_authdly[0];
sys_authdly[0] = xmt_tx.l_uf;
if (sys_authdly[0] < sys_authdly[1])
sys_authdelay.l_uf = sys_authdly[0];
else
sys_authdelay.l_uf = sys_authdly[1];
peer->sent++;
#ifdef OPENSSL
#ifdef DEBUG
if (debug)
printf(
"transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d index %d\n",
current_time, ntoa(&peer->dstadr->sin),
ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen -
authlen, authlen, peer->keynumber);
#endif
#else
#ifdef DEBUG
if (debug)
printf(
"transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d\n",
current_time, ntoa(&peer->dstadr->sin),
ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen -
authlen, authlen);
#endif
#endif
}
static void
fast_xmit(
struct recvbuf *rbufp,
int xmode,
keyid_t xkeyid,
int mask
)
{
struct pkt xpkt;
struct pkt *rpkt;
l_fp xmt_ts;
l_fp xmt_tx;
int sendlen, authlen;
#ifdef OPENSSL
u_int32 temp32;
#endif
rpkt = &rbufp->recv_pkt;
if (rbufp->dstadr->flags & INT_MULTICAST)
rbufp->dstadr = findinterface(&rbufp->recv_srcadr);
if (mask & (RES_DONTTRUST | RES_LIMITED)) {
char *code = "????";
if (mask & RES_LIMITED) {
sys_limitrejected++;
code = "RATE";
} else if (mask & RES_DONTTRUST) {
sys_restricted++;
code = "DENY";
}
if (sys_kod == 0 || !(mask & RES_DEMOBILIZE))
return;
sys_kod--;
memcpy(&xpkt.refid, code, 4);
xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC,
PKT_VERSION(rpkt->li_vn_mode), xmode);
xpkt.stratum = STRATUM_UNSPEC;
} 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.refid = sys_refid;
}
xpkt.ppoll = rpkt->ppoll;
xpkt.precision = sys_precision;
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);
sendlen = LEN_PKT_NOMAC;
if (rbufp->recv_length == sendlen) {
get_systime(&xmt_ts);
HTONL_FP(&xmt_ts, &xpkt.xmt);
sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, &xpkt,
sendlen);
#ifdef DEBUG
if (debug)
printf("transmit: at %ld %s->%s mode %d\n",
current_time, stoa(&rbufp->dstadr->sin),
stoa(&rbufp->recv_srcadr), xmode);
#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 >= (int)(sendlen + MAX_MAC_LEN + 2 *
sizeof(u_int32))) {
session_key(&rbufp->dstadr->sin,
&rbufp->recv_srcadr, xkeyid, 0, 2);
temp32 = CRYPTO_RESP;
rpkt->exten[0] |= htonl(temp32);
sendlen += crypto_xmit(&xpkt,
&rbufp->recv_srcadr, sendlen,
(struct exten *)rpkt->exten, cookie);
} else {
session_key(&rbufp->dstadr->sin,
&rbufp->recv_srcadr, xkeyid, cookie, 2);
}
}
#endif
get_systime(&xmt_ts);
L_ADD(&xmt_ts, &sys_authdelay);
HTONL_FP(&xmt_ts, &xpkt.xmt);
authlen = authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen);
sendlen += authlen;
#ifdef OPENSSL
if (xkeyid > NTP_MAXKEY)
authtrust(xkeyid, 0);
#endif
get_systime(&xmt_tx);
if (sendlen > sizeof(xpkt)) {
msyslog(LOG_ERR, "buffer overflow %u", sendlen);
exit (-1);
}
sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, &xpkt, sendlen);
L_SUB(&xmt_tx, &xmt_ts);
L_ADD(&xmt_tx, &sys_authdelay);
sys_authdly[1] = sys_authdly[0];
sys_authdly[0] = xmt_tx.l_uf;
if (sys_authdly[0] < sys_authdly[1])
sys_authdelay.l_uf = sys_authdly[0];
else
sys_authdelay.l_uf = sys_authdly[1];
#ifdef DEBUG
if (debug)
printf(
"transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d\n",
current_time, ntoa(&rbufp->dstadr->sin),
ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen -
authlen, authlen);
#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;
#ifdef DEBUG
if (debug)
printf("key_expire: at %lu\n", current_time);
#endif
}
#endif
static int
peer_unfit(
struct peer *peer
)
{
return (!peer->reach || (peer->stratum > 1 && peer->refid ==
peer->dstadr->addr_refid) || peer->leap == LEAP_NOTINSYNC ||
peer->stratum >= STRATUM_UNSPEC || root_distance(peer) >=
MAXDISTANCE + 2. * clock_phi * ULOGTOD(sys_poll) ||
peer->flags & FLAG_NOSELECT );
}
#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;
get_systime(&last);
tick = MAXSTEP;
for (i = 0; i < MINLOOPS;) {
get_systime(&val);
diff = val;
L_SUB(&diff, &last);
last = val;
LFPTOD(&diff, dtemp);
if (dtemp < MINSTEP)
continue;
i++;
if (dtemp < tick)
tick = dtemp;
}
NLOG(NLOG_SYSEVENT)
msyslog(LOG_INFO, "precision = %.3f usec", tick * 1e6);
for (i = 0; tick <= 1; i++)
tick *= 2;
if (tick - 1. > 1. - tick / 2)
i--;
return (-i);
}
void
kod_proto(void)
{
sys_kod = sys_kod_rate;
}
void
init_proto(void)
{
l_fp dummy;
int i;
sys_leap = LEAP_NOTINSYNC;
sys_stratum = STRATUM_UNSPEC;
memcpy(&sys_refid, "INIT", 4);
sys_precision = (s_char)default_get_precision();
sys_jitter = LOGTOD(sys_precision);
sys_rootdelay = 0;
sys_rootdispersion = 0;
L_CLR(&sys_reftime);
sys_peer = NULL;
sys_survivors = 0;
get_systime(&dummy);
sys_manycastserver = 0;
sys_bclient = 0;
sys_bdelay = DEFBROADDELAY;
sys_calldelay = BURST_DELAY;
sys_authenticate = 1;
L_CLR(&sys_authdelay);
sys_authdly[0] = sys_authdly[1] = 0;
sys_stattime = 0;
proto_clr_stats();
for (i = 0; i < MAX_TTL; i++) {
sys_ttl[i] = (u_char)((i * 256) / MAX_TTL);
sys_ttlmax = i;
}
#ifdef OPENSSL
sys_automax = 1 << NTP_AUTOMAX;
#endif
ntp_enable = 1;
#ifndef KERNEL_FLL_BUG
kern_enable = 1;
#endif
pps_enable = 0;
stats_control = 1;
}
void
proto_config(
int item,
u_long value,
double dvalue,
struct sockaddr_storage* svalue
)
{
switch (item) {
case PROTO_KERNEL:
kern_enable = (int)value;
break;
case PROTO_NTP:
ntp_enable = (int)value;
break;
case PROTO_MONITOR:
if (value)
mon_start(MON_ON);
else
mon_stop(MON_ON);
break;
case PROTO_FILEGEN:
stats_control = (int)value;
break;
case PROTO_BROADCLIENT:
sys_bclient = (int)value;
if (value)
io_setbclient();
else
io_unsetbclient();
break;
case PROTO_MULTICAST_ADD:
if (svalue)
io_multicast_add(*svalue);
break;
case PROTO_MULTICAST_DEL:
if (svalue)
io_multicast_del(*svalue);
break;
case PROTO_BROADDELAY:
sys_bdelay = dvalue;
break;
case PROTO_CALLDELAY:
sys_calldelay = (int)value;
break;
case PROTO_AUTHENTICATE:
sys_authenticate = (int)value;
break;
case PROTO_PPS:
pps_enable = (int)value;
break;
case PROTO_MINCLOCK:
sys_minclock = (int)dvalue;
break;
case PROTO_MINSANE:
sys_minsane = (int)dvalue;
break;
case PROTO_FLOOR:
sys_floor = (int)dvalue;
break;
case PROTO_CEILING:
sys_ceiling = (int)dvalue;
break;
case PROTO_COHORT:
sys_cohort= (int)dvalue;
break;
case PROTO_ADJ:
sys_tick = dvalue;
break;
#ifdef REFCLOCK
case PROTO_CAL:
cal_enable = (int)value;
break;
#endif
default:
msyslog(LOG_INFO,
"proto_config: illegal item %d, value %ld",
item, value);
}
}
void
proto_clr_stats(void)
{
sys_stattime = current_time;
sys_received = 0;
sys_processed = 0;
sys_newversionpkt = 0;
sys_oldversionpkt = 0;
sys_unknownversion = 0;
sys_restricted = 0;
sys_badlength = 0;
sys_badauth = 0;
sys_limitrejected = 0;
}