+* much cleanup, fixes, and changes from Dave Mills.
* ntp_control.c: LEAPTAB is a filestamp, not an unsigned. From Dave Mills.
* ntp_config.c: ntp_minpoll fixes from Dave Mills.
* ntp-keygen updates from Dave Mills.
struct pkey_info *pkinfo = NULL; /* key info/value cache */
struct value hostval; /* host value */
struct value pubkey; /* public key */
-struct value tai_leap; /* leapseconds table */
+struct value tai_leap; /* leapseconds values */
struct pkey_info *iffkey_info = NULL; /* IFF keys */
struct pkey_info *gqkey_info = NULL; /* GQ keys */
struct pkey_info *mvkey_info = NULL; /* MV keys */
*/
if (peer->pkey == NULL) {
ptr = (u_char *)xinfo->cert.ptr;
- cert = d2i_X509(NULL,
- (const u_char **)&ptr,
+ cert = d2i_X509(NULL, &ptr,
ntohl(xinfo->cert.vallen));
peer->pkey = X509_get_pubkey(cert);
X509_free(cert);
break;
/*
- * Install leapseconds table in symmetric modes. This
+ * Install leapseconds values in symmetric modes. This
* table is proventicated to the NIST primary servers,
* either by copying the file containing the table from
* a NIST server to a trusted server or directly using
/*
* Pass the extension field to the transmit
- * side. Continue below if a leapseconds table
+ * side. Continue below if leapseconds values
* accompanies the message.
*/
fp = emalloc(len);
/*
* If this is a response, discard the message if
* signature not verified with respect to the
- * leapsecond table values.
+ * leapseconds values.
*/
if (peer->cmmd == NULL) {
if ((rval = crypto_verify(ep, NULL,
leap_expire = ntohl(ep->pkt[2]);
crypto_update();
msyslog(LOG_NOTICE,
- "crypto: leap epoch %lu TAI offset %d expire %lu",
- leap_sec, leap_tai, leap_expire); } else if (ntohl(ep->pkt[2]) < leap_expire) {
- msyslog(LOG_ERR,
- "crypto: stale leap second values");
+ "leap epoch %lu expire %lu TAI offset %d from %s",
+ leap_sec, leap_expire, leap_tai,
+ stoa(&peer->srcadr));
}
peer->crypto |= CRYPTO_FLAG_LEAP;
peer->flash &= ~TEST8;
*/
case CRYPTO_CERT | CRYPTO_RESP:
vallen = ntohl(ep->vallen);
- if (vallen == 8) {
- strcpy(certname, sys_hostname);
- } else if (vallen == 0 || vallen > MAXHOSTNAME) {
+ if (vallen == 0 || vallen > MAXHOSTNAME) {
rval = XEVNT_LEN;
break;
}
/*
- * Find all certificates with matching subject. If a
- * self-signed, trusted certificate is found, use that.
- * If not, use the last non self-signed one with
- * matching subject. A private certificate is never
- * divulged or signed.
+ * Find all public valid certificates with matching
+ * subject. If a self-signed, trusted certificate is
+ * found, use that certificate. If not, use the last non
+ * self-signed certificate.
*/
xp = yp = NULL;
for (cp = cinfo; cp != NULL; cp = cp->link) {
- if (cp->flags & CERT_PRIV)
+ if (cp->flags & (CERT_PRIV | CERT_ERROR))
continue;
if (strcmp(certname, cp->subject) != 0)
break;
/*
- * Send leapseconds table and signature. Use the values from the
- * tai structure. If no table has been loaded, just send an
+ * Send leapseconds values and signature. Use the values from
+ * the tai structure. If no table has been loaded, just send an
* empty request.
*/
case CRYPTO_TAI:
*/
len = ntohl(ep->vallen);
ptr = (u_char *)ep->pkt;
- pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, (const u_char **)&ptr,
- len);
+ pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &ptr, len);
if (pkey == NULL) {
msyslog(LOG_ERR, "crypto_encrypt: %s",
ERR_error_string(ERR_get_error(), NULL));
if (peer->ident_pkey != NULL)
return (CRYPTO_MV);
}
- msyslog(LOG_INFO,
+ msyslog(LOG_NOTICE,
"crypto_ident: no identity parameters found for group %s",
peer->issuer);
return (CRYPTO_NULL);
EVP_SignUpdate(&ctx, tai_leap.ptr, len);
if (EVP_SignFinal(&ctx, tai_leap.sig, &len, sign_pkey))
tai_leap.siglen = htonl(len);
- if (leap_expire > 0)
+ if (leap_sec > 0)
crypto_flags |= CRYPTO_FLAG_TAI;
snprintf(statstr, NTP_MAXSTRLEN, "update at %lu ts %u",
current_time, ntohl(hostval.tstamp));
***********************************************************************
*
* The Schnorr (IFF) identity scheme is intended for use when
- * the ntp-genkeys program does not generate the certificates used in
- * the protocol and the group key cannot be conveyed in the certificate
- * itself. For this purpose, new generations of IFF values must be
- * securely transmitted to all members of the group before use. The
- * scheme is self contained and independent of new generations of host
- * keys, sign keys and certificates.
- *
- * The IFF identity scheme is based on DSA cryptography and algorithms
- * described in Stinson p. 285. The IFF values hide in a DSA cuckoo
- * structure, but only the primes and generator are used. The p is a
- * 512-bit prime, q a 160-bit prime that divides p - 1 and is a qth root
- * of 1 mod p; that is, g^q = 1 mod p. The TA rolls primvate random
- * group key b disguised as a DSA structure member, then computes public
- * key g^(q - b). These values are shared only among group members and
- * never revealed in messages. Alice challenges Bob to confirm identity
- * using the protocol described below.
+ * certificates are generated by some other trusted certificate
+ * authority and the certificate cannot be used to convey public
+ * parameters. There are two kinds of files: encrypted server files that
+ * contain private and public values and nonencrypted client files that
+ * contain only public values. New generations of server files must be
+ * securely transmitted to all servers of the group; client files can be
+ * distributed by any means. The scheme is self contained and
+ * independent of new generations of host keys, sign keys and
+ * certificates.
+ *
+ * The IFF values hide in a DSA cuckoo structure which uses the same
+ * parameters. The values are used by an identity scheme based on DSA
+ * cryptography and described in Stimson p. 285. The p is a 512-bit
+ * prime, g a generator of Zp* and q a 160-bit prime that divides p - 1
+ * and is a qth root of 1 mod p; that is, g^q = 1 mod p. The TA rolls a
+ * private random group key b (0 < b < q) and public key v = g^b, then
+ * sends (p, q, g, b) to the servers and (p, q, g, v) to the clients.
+ * Alice challenges Bob to confirm identity using the protocol described
+ * below.
*
* How it works
*
* The scheme goes like this. Both Alice and Bob have the public primes
* p, q and generator g. The TA gives private key b to Bob and public
- * key v = g^(q - a) mod p to Alice.
- *
- * Alice rolls new random challenge r and sends to Bob in the IFF
- * request message. Bob rolls new random k, then computes y = k + b r
- * mod q and x = g^k mod p and sends (y, hash(x)) to Alice in the
- * response message. Besides making the response shorter, the hash makes
- * it effectivey impossible for an intruder to solve for b by observing
- * a number of these messages.
+ * key v to Alice.
+ *
+ * Alice rolls new random challenge r (o < r < q) and sends to Bob in
+ * the IFF request message. Bob rolls new random k (0 < k < q), then
+ * computes y = k + b r mod q and x = g^k mod p and sends (y, hash(x))
+ * to Alice in the response message. Besides making the response
+ * shorter, the hash makes it effectivey impossible for an intruder to
+ * solve for b by observing a number of these messages.
*
* Alice receives the response and computes g^y v^r mod p. After a bit
* of algebra, this simplifies to g^k. If the hash of this result
return (XEVNT_ID);
if ((dsa = peer->ident_pkey->pkey->pkey.dsa) == NULL) {
- msyslog(LOG_INFO, "crypto_alice: defective key");
+ msyslog(LOG_NOTICE, "crypto_alice: defective key");
return (XEVNT_PUB);
}
* happened or we are being tormented.
*/
if (iffkey_info == NULL) {
- msyslog(LOG_INFO, "crypto_bob: scheme unavailable");
+ msyslog(LOG_NOTICE, "crypto_bob: scheme unavailable");
return (XEVNT_ID);
}
dsa = iffkey_info->pkey->pkey.dsa;
* something awful happened or we are being tormented.
*/
if (peer->ident_pkey == NULL) {
- msyslog(LOG_INFO, "crypto_iff: scheme unavailable");
+ msyslog(LOG_NOTICE, "crypto_iff: scheme unavailable");
return (XEVNT_ID);
}
if (ntohl(ep->fstamp) != peer->ident_pkey->fstamp) {
- msyslog(LOG_INFO, "crypto_iff: invalid filestamp %u",
+ msyslog(LOG_NOTICE, "crypto_iff: invalid filestamp %u",
ntohl(ep->fstamp));
return (XEVNT_FSP);
}
if ((dsa = peer->ident_pkey->pkey->pkey.dsa) == NULL) {
- msyslog(LOG_INFO, "crypto_iff: defective key");
+ msyslog(LOG_NOTICE, "crypto_iff: defective key");
return (XEVNT_PUB);
}
if (peer->iffval == NULL) {
- msyslog(LOG_INFO, "crypto_iff: missing challenge");
+ msyslog(LOG_NOTICE, "crypto_iff: missing challenge");
return (XEVNT_ID);
}
if (temp == 0)
return (XEVNT_OK);
- msyslog(LOG_INFO, "crypto_iff: identity not verified");
+ msyslog(LOG_NOTICE, "crypto_iff: identity not verified");
return (XEVNT_ID);
}
***********************************************************************
*
* The Guillou-Quisquater (GQ) identity scheme is intended for use when
- * the ntp-genkeys program generates the certificates used in the
- * protocol and the group key can be conveyed in a certificate extension
- * field. The scheme is self contained and independent of new
- * generations of host keys, sign keys and certificates.
- *
- * The GQ identity scheme is based on RSA cryptography and algorithms
- * described in Stinson p. 300 (with errors). The GQ values hide in a
- * RSA cuckoo structure, but only the modulus is used. The 512-bit
- * public modulus is n = p q, where p and q are secret large primes. The
- * TA rolls random group key b disguised as a RSA structure member.
- * Except for the public key, these values are shared only among group
- * members and never revealed in messages.
- *
- * When rolling new certificates, Bob recomputes the private and
+ * the certificate can be used to convey public parameters. The scheme
+ * uses a X509v3 certificate extension field do convey the public key of
+ * a private key known only to servers. There are two kinds of files:
+ * encrypted server files that contain private and public values and
+ * nonencrypted client files that contain only public values. New
+ * generations of server files must be securely transmitted to all
+ * servers of the group; client files can be distributed by any means.
+ * The scheme is self contained and independent of new generations of
+ * host keys and sign keys. The scheme is self contained and independent
+ * of new generations of host keys and sign keys.
+ *
+ * The GQ parameters hide in a RSA cuckoo structure which uses the same
+ * parameters. The values are used by an identity scheme based on RSA
+ * cryptography and described in Stimson p. 300 (with errors). The 512-
+ * bit public modulus is n = p q, where p and q are secret large primes.
+ * The TA rolls private random group key b as RSA exponent. These values
+ * are known to all group members.
+ *
+ * When rolling new certificates, a server recomputes the private and
* public keys. The private key u is a random roll, while the public key
* is the inverse obscured by the group key v = (u^-1)^b. These values
* replace the private and public keys normally generated by the RSA
return (XEVNT_ID);
if ((rsa = peer->ident_pkey->pkey->pkey.rsa) == NULL) {
- msyslog(LOG_INFO, "crypto_alice2: defective key");
+ msyslog(LOG_NOTICE, "crypto_alice2: defective key");
return (XEVNT_PUB);
}
* happened or we are being tormented.
*/
if (gqkey_info == NULL) {
- msyslog(LOG_INFO, "crypto_bob2: scheme unavailable");
+ msyslog(LOG_NOTICE, "crypto_bob2: scheme unavailable");
return (XEVNT_ID);
}
rsa = gqkey_info->pkey->pkey.rsa;
* the remote parameter file if the keys have been refreshed.
*/
if (peer->ident_pkey == NULL) {
- msyslog(LOG_INFO, "crypto_gq: scheme unavailable");
+ msyslog(LOG_NOTICE, "crypto_gq: scheme unavailable");
return (XEVNT_ID);
}
if (ntohl(ep->fstamp) < peer->ident_pkey->fstamp) {
- msyslog(LOG_INFO, "crypto_gq: invalid filestamp %u",
+ msyslog(LOG_NOTICE, "crypto_gq: invalid filestamp %u",
ntohl(ep->fstamp));
return (XEVNT_FSP);
}
if ((rsa = peer->ident_pkey->pkey->pkey.rsa) == NULL) {
- msyslog(LOG_INFO, "crypto_gq: defective key");
+ msyslog(LOG_NOTICE, "crypto_gq: defective key");
return (XEVNT_PUB);
}
if (peer->iffval == NULL) {
- msyslog(LOG_INFO, "crypto_gq: missing challenge");
+ msyslog(LOG_NOTICE, "crypto_gq: missing challenge");
return (XEVNT_ID);
}
* Compute v^r y^b mod n.
*/
if (peer->grpkey == NULL) {
- msyslog(LOG_INFO, "crypto_gq: missing group key");
+ msyslog(LOG_NOTICE, "crypto_gq: missing group key");
return (XEVNT_ID);
}
BN_mod_exp(v, peer->grpkey, peer->iffval, rsa->n, bctx);
if (temp == 0)
return (XEVNT_OK);
- msyslog(LOG_INFO, "crypto_gq: identity not verified");
+ msyslog(LOG_NOTICE, "crypto_gq: identity not verified");
return (XEVNT_ID);
}
* scheme *
* *
***********************************************************************
- */
-/*
+ *
* The Mu-Varadharajan (MV) cryptosystem was originally intended when
* servers broadcast messages to clients, but clients never send
* messages to servers. There is one encryption key for the server and a
* Varadharajan: Robust and Secure Broadcasting, Proc. Indocrypt 2001,
* 223-231. The paper has significant errors and serious omissions.
*
- * Let q be the product of n distinct primes s'[j] (j = 1...n), where
- * each s'[j] has m significant bits. Let p be a prime p = 2 * q + 1, so
- * that q and each s'[j] divide p - 1 and p has M = n * m + 1
- * significant bits. The elements x mod q of Zq with the elements 2 and
- * the primes removed form a field Zq* valid for polynomial arithetic.
- * Let g be a generator of Zp; that is, gcd(g, p - 1) = 1 and g^q = 1
- * mod p. We expect M to be in the 500-bit range and n relatively small,
- * like 25, so the likelihood of a randomly generated element of x mod q
- * of Zq colliding with a factor of p - 1 is very small and can be
- * avoided. Associated with each s'[j] is an element s[j] such that s[j]
- * s'[j] = s'[j] mod q. We find s[j] as the quotient (q + s'[j]) /
- * s'[j]. These are the parameters of the scheme and they are expensive
- * to compute.
+ * Let q be the product of n distinct primes s1[j] (j = 1...n), where
+ * each s1[j] has m significant bits. Let p be a prime p = 2 * q + 1, so
+ * that q and each s1[j] divide p - 1 and p has M = n * m + 1
+ * significant bits. Let g be a generator of Zp; that is, gcd(g, p - 1)
+ * = 1 and g^q = 1 mod p. We do modular arithmetic over Zq and then
+ * project into Zp* as exponents of g. Sometimes we have to compute an
+ * inverse b^-1 of random b in Zq, but for that purpose we require
+ * gcd(b, q) = 1. We expect M to be in the 500-bit range and n
+ * relatively small, like 30. These are the parameters of the scheme and
+ * they are expensive to compute.
*
* We set up an instance of the scheme as follows. A set of random
* values x[j] mod q (j = 1...n), are generated as the zeros of a
* pairs (xbar[j], xhat[j]) (j = 1...n) of private client keys are used
* to construct the decryption keys. The devil is in the details.
*
+ * This routine generates a private server encryption file including the
+ * private encryption key E and partial decryption keys gbar and ghat.
+ * It then generates public client decryption files including the public
+ * keys xbar[j] and xhat[j] for each client j. The partial decryption
+ * files are used to compute the inverse of E. These values are suitably
+ * blinded so secrets are not revealed.
+ *
* The distinguishing characteristic of this scheme is the capability to
* revoke keys. Included in the calculation of E, gbar and ghat is the
- * product s = prod(s'[j]) (j = 1...n) above. If the factor s'[j] is
+ * product s = prod(s1[j]) (j = 1...n) above. If the factor s1[j] is
* subsequently removed from the product and E, gbar and ghat
* recomputed, the jth client will no longer be able to compute E^-1 and
- * thus unable to decrypt the block.
+ * thus unable to decrypt the messageblock.
*
* How it works
*
- * The scheme goes like this. Bob has the server values (p, A, q, gbar,
- * ghat) and Alice the client values (p, xbar, xhat).
+ * The scheme goes like this. Bob has the server values (p, E, q, gbar,
+ * ghat) and Alice has the client values (p, xbar, xhat).
*
- * Alice rolls new random challenge r (0 < r < p) and sends to Bob in
- * the MV request message. Bob rolls new random k (0 < k < q), encrypts
- * y = A^k mod p (a permutation) and sends (hash(y), gbar^k, ghat^k) to
- * Alice.
+ * Alice rolls new random nonce r mod p and sends to Bob in the MV
+ * request message. Bob rolls random nonce k mod q, encrypts y = r E^k
+ * mod p and sends (y, gbar^k, ghat^k) to Alice.
*
- * Alice receives the response and computes the decryption key (the
- * inverse permutation) from previously obtained (xbar, xhat) and
- * (gbar^k, ghat^k) in the message. She computes the inverse, which is
- * unique by reasons explained in the ntp-keygen.c program sources. If
- * the hash of this result matches hash(y), Alice knows that Bob has the
- * group key b. The signed response binds this knowledge to Bob's
- * private key and the public key previously received in his
- * certificate.
+ * Alice receives the response and computes the inverse (E^k)^-1 from
+ * the partial decryption keys gbar^k, ghat^k, xbar and xhat. She then
+ * decrypts y and verifies it matches the original r. The signed
+ * response binds this knowledge to Bob's private key and the public key
+ * previously received in his certificate.
*
* crypto_alice3 - construct Alice's challenge in MV scheme
*
return (XEVNT_ID);
if ((dsa = peer->ident_pkey->pkey->pkey.dsa) == NULL) {
- msyslog(LOG_INFO, "crypto_alice3: defective key");
+ msyslog(LOG_NOTICE, "crypto_alice3: defective key");
return (XEVNT_PUB);
}
* happened or we are being tormented.
*/
if (mvkey_info == NULL) {
- msyslog(LOG_INFO, "crypto_bob3: scheme unavailable");
+ msyslog(LOG_NOTICE, "crypto_bob3: scheme unavailable");
return (XEVNT_ID);
}
dsa = mvkey_info->pkey->pkey.dsa;
/*
* Bob rolls random k (0 < k < q), making sure it is not a
- * factor of q. He then computes y = A^k r and sends (hash(y),
- * gbar^k, ghat^k) to Alice.
+ * factor of q. He then computes y = r A^k and sends (y, gbar^k,
+ * and ghat^k) to Alice.
*/
bctx = BN_CTX_new(); k = BN_new(); u = BN_new();
sdsa = DSA_new();
if (BN_is_one(u))
break;
}
- BN_mod_exp(u, dsa->g, k, dsa->p, bctx); /* A r */
- BN_mod_mul(u, u, r, dsa->p, bctx);
- bighash(u, sdsa->p);
+ BN_mod_exp(u, dsa->g, k, dsa->p, bctx); /* A^k r */
+ BN_mod_mul(sdsa->p, u, r, dsa->p, bctx);
BN_mod_exp(sdsa->q, dsa->priv_key, k, dsa->p, bctx); /* gbar */
BN_mod_exp(sdsa->g, dsa->pub_key, k, dsa->p, bctx); /* ghat */
BN_CTX_free(bctx); BN_free(k); BN_free(r); BN_free(u);
#ifdef DEBUG
if (debug > 1)
- DSA_print_fp(stdout, dsa, 0);
+ DSA_print_fp(stdout, sdsa, 0);
#endif
/*
* something awful happened or we are being tormented.
*/
if (peer->ident_pkey == NULL) {
- msyslog(LOG_INFO, "crypto_mv: scheme unavailable");
+ msyslog(LOG_NOTICE, "crypto_mv: scheme unavailable");
return (XEVNT_ID);
}
if (ntohl(ep->fstamp) != peer->ident_pkey->fstamp) {
- msyslog(LOG_INFO, "crypto_mv: invalid filestamp %u",
+ msyslog(LOG_NOTICE, "crypto_mv: invalid filestamp %u",
ntohl(ep->fstamp));
return (XEVNT_FSP);
}
if ((dsa = peer->ident_pkey->pkey->pkey.dsa) == NULL) {
- msyslog(LOG_INFO, "crypto_mv: defective key");
+ msyslog(LOG_NOTICE, "crypto_mv: defective key");
return (XEVNT_PUB);
}
if (peer->iffval == NULL) {
- msyslog(LOG_INFO, "crypto_mv: missing challenge");
+ msyslog(LOG_NOTICE, "crypto_mv: missing challenge");
return (XEVNT_ID);
}
/*
- * Extract the (hash(y), gbar, ghat) values from the response.
+ * Extract the y, gbar and ghat values from the response.
*/
bctx = BN_CTX_new(); k = BN_new(); u = BN_new(); v = BN_new();
len = ntohl(ep->vallen);
}
/*
- * Compute (gbar^xhat ghat^xbar)^-1 mod p.
+ * Compute (gbar^xhat ghat^xbar) mod p.
*/
BN_mod_exp(u, sdsa->q, dsa->pub_key, dsa->p, bctx);
BN_mod_exp(v, sdsa->g, dsa->priv_key, dsa->p, bctx);
BN_mod_mul(u, u, v, dsa->p, bctx);
- BN_mod_inverse(u, u, dsa->p, bctx);
- BN_mod_mul(v, u, peer->iffval, dsa->p, bctx);
+ BN_mod_mul(u, u, sdsa->p, dsa->p, bctx);
/*
- * The result should match the hash of r mod p.
+ * The result should match r.
*/
- bighash(v, v);
- temp = BN_cmp(v, sdsa->p);
+ temp = BN_cmp(u, peer->iffval);
BN_CTX_free(bctx); BN_free(k); BN_free(u); BN_free(v);
BN_free(peer->iffval);
peer->iffval = NULL;
if (temp == 0)
return (XEVNT_OK);
- msyslog(LOG_INFO, "crypto_mv: identity not verified");
+ msyslog(LOG_NOTICE, "crypto_mv: identity not verified");
return (XEVNT_ID);
}
return (XEVNT_TSP);
ptr = (u_char *)ep->pkt;
- if ((req = d2i_X509(NULL, (const u_char **)&ptr,
- ntohl(ep->vallen))) == NULL) {
+ if ((req = d2i_X509(NULL, &ptr, ntohl(ep->vallen))) == NULL) {
msyslog(LOG_ERR, "cert_sign: %s",
ERR_error_string(ERR_get_error(), NULL));
return (XEVNT_CRT);
}
/*
- * Generate X509 certificate signed by this server. For this
- * purpose the issuer name is the server name. Also copy any
- * extensions that might be present.
+ * Generate X509 certificate signed by this server. If this is a
+ * trusted host, the issuer name is the group name; otherwise,
+ * it is the host name. Also copy any extensions that might be
+ * present.
*/
cert = X509_new();
X509_set_version(cert, X509_get_version(req));
X509_gmtime_adj(X509_get_notAfter(cert), YEAR);
subj = X509_get_issuer_name(cert);
X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC,
- (u_char *)sys_hostname, strlen(sys_hostname), -1, 0);
+ hostval.ptr, strlen(hostval.ptr), -1, 0);
subj = X509_get_subject_name(req);
X509_set_subject_name(cert, subj);
X509_set_pubkey(cert, pkey);
vp->vallen = htonl(len);
vp->ptr = emalloc(len);
ptr = vp->ptr;
- i2d_X509(cert, (u_char **)&ptr);
+ i2d_X509(cert, &ptr);
vp->siglen = 0;
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
return (XEVNT_OK);
ptr = (u_char *)cinf->cert.ptr;
- cert = d2i_X509(NULL, (const u_char **)&ptr,
- ntohl(cinf->cert.vallen));
+ cert = d2i_X509(NULL, &ptr, ntohl(cinf->cert.vallen));
if (cert == NULL || !X509_verify(cert, pkey))
return (XEVNT_VFY);
X509_EXTENSION *ext; /* X509v3 extension */
struct cert_info *ret; /* certificate info/value */
BIO *bp;
- X509V3_EXT_METHOD *method;
char pathbuf[MAXFILENAME];
- u_char *uptr;
- const char *ptr;
+ u_char *ptr;
int temp, cnt, i;
/*
* Decode ASN.1 objects and construct certificate structure.
*/
- uptr = asn1cert;
- if ((cert = d2i_X509(NULL, (const u_char **)&uptr, len)) ==
- NULL) {
+ ptr = asn1cert;
+ if ((cert = d2i_X509(NULL, &ptr, len)) == NULL) {
msyslog(LOG_ERR, "cert_parse: %s",
ERR_error_string(ERR_get_error(), NULL));
return (NULL);
MAXFILENAME);
ptr = strstr(pathbuf, "CN=");
if (ptr == NULL) {
- msyslog(LOG_INFO, "cert_parse: invalid subject %s",
+ msyslog(LOG_NOTICE, "cert_parse: invalid subject %s",
pathbuf);
cert_free(ret);
X509_free(cert);
X509_NAME_oneline(X509_get_issuer_name(cert), pathbuf,
MAXFILENAME);
if ((ptr = strstr(pathbuf, "CN=")) == NULL) {
- msyslog(LOG_INFO, "cert_parse: invalid issuer %s",
+ msyslog(LOG_NOTICE, "cert_parse: invalid issuer %s",
pathbuf);
cert_free(ret);
X509_free(cert);
cnt = X509_get_ext_count(cert);
for (i = 0; i < cnt; i++) {
ext = X509_get_ext(cert, i);
- method = X509V3_EXT_get(ext);
temp = OBJ_obj2nid(ext->object);
switch (temp) {
* If certificate is self signed, verify signature.
*/
if (!X509_verify(cert, ret->pkey)) {
- msyslog(LOG_INFO,
+ msyslog(LOG_NOTICE,
"cert_parse: signature not verified %s",
ret->subject);
cert_free(ret);
/*
* Check for a certificate loop.
*/
- if (strcmp(sys_hostname, ret->issuer) == 0) {
- msyslog(LOG_INFO,
+ if (strcmp(hostval.ptr, ret->issuer) == 0) {
+ msyslog(LOG_NOTICE,
"cert_parse: certificate trail loop %s",
ret->subject);
cert_free(ret);
* be retroactive.
*/
if (ret->first > ret->last || ret->first < fstamp) {
- msyslog(LOG_INFO,
+ msyslog(LOG_NOTICE,
"cert_parse: invalid times %s first %u last %u fstamp %u",
ret->subject, ret->first, ret->last, fstamp);
cert_free(ret);
fclose(str);
free(header);
if (strcmp(name, "CERTIFICATE") != 0) {
- msyslog(LOG_INFO, "crypto_cert: wrong PEM type %s",
+ msyslog(LOG_NOTICE, "crypto_cert: wrong PEM type %s",
name);
free(name);
free(data);
* the case of multiple crypto commands.
*/
if (crypto_flags & CRYPTO_FLAG_ENAB) {
- msyslog(LOG_ERR,
+ msyslog(LOG_NOTICE,
"crypto_setup: spurious crypto command");
return;
}
host_pkey = pinfo->pkey;
sign_pkey = host_pkey;
hostval.fstamp = htonl(pinfo->fstamp);
- hostval.vallen = htonl(strlen(sys_hostname));
- hostval.ptr = (u_char *)sys_hostname;
/*
* Construct public key extension field for agreement scheme.
filename);
exit (-1);
}
+ cert_host = cinfo;
sign_digest = cinfo->digest;
if (cinfo->flags & CERT_PRIV)
crypto_flags |= CRYPTO_FLAG_PRIV;
- /*
- * The subject and host names must match.
- */
- if (!(cinfo->flags & CERT_PRIV) && strcmp(cinfo->subject,
- sys_hostname) != 0) {
- msyslog(LOG_ERR,
- "crypto_setup: certificate %s not for this host %s",
- filename, sys_hostname);
- exit (-1);
- }
-
/*
* The certificate must be self-signed.
*/
filename);
exit (-1);
}
+ hostval.vallen = htonl(strlen(cinfo->subject));
+ hostval.ptr = cinfo->subject;
/*
- * On trusted hosts the subject and group names must match.
+ * If trusted certificate, the subject name must match the group
+ * name.
*/
if (cinfo->flags & CERT_TRUST) {
if (sys_groupname == NULL) {
+ sys_groupname = hostval.ptr;
+ } else if (strcmp(hostval.ptr, sys_groupname) != 0) {
msyslog(LOG_ERR,
- "crypto_setup: trusted host %s missing group name",
- cinfo->subject);
- exit (-1);
- }
- if (strcmp(cinfo->subject, sys_groupname) != 0) {
- msyslog(LOG_ERR,
- "crypto_setup: trusted host %s name and group name %s mismatch",
- cinfo->subject, sys_groupname);
+ "crypto_setup: trusted certificate name %s does not match group name %s",
+ hostval.ptr, sys_groupname);
exit (-1);
}
}
- cert_host = cinfo;
if (sys_groupname != NULL) {
/*
* Load optional IFF parameters from file
- * "ntpkey_iff_<groupname>".
+ * "ntpkey_iffkey_<groupname>".
*/
snprintf(filename, MAXFILENAME, "ntpkey_iffkey_%s",
sys_groupname);
/*
* Load optional GQ parameters from file
- * "ntpkey_gq_<groupname>".
+ * "ntpkey_gqkey_<groupname>".
*/
snprintf(filename, MAXFILENAME, "ntpkey_gqkey_%s",
sys_groupname);
/*
* Load optional MV parameters from file
- * "ntpkey_mv_<groupname>".
+ * "ntpkey_mvkey_<groupname>".
*/
snprintf(filename, MAXFILENAME, "ntpkey_mvkey_%s",
sys_groupname);
intval[TOK_VERSION], name);
resolver_exit(1);
}
- if (intval[TOK_MINPOLL] < NTP_MINPOLL ||
- intval[TOK_MINPOLL] > NTP_MAXPOLL) {
+ if (intval[TOK_MINPOLL] < ntp_minpoll ||
+ intval[TOK_MINPOLL] > ntp_minpoll) {
+
msyslog(LOG_ERR, "invalid MINPOLL value (%ld) in file %s",
intval[TOK_MINPOLL], name);
resolver_exit(1);
}
- if (intval[TOK_MAXPOLL] < NTP_MINPOLL ||
+ if (intval[TOK_MAXPOLL] < ntp_minpoll ||
intval[TOK_MAXPOLL] > NTP_MAXPOLL) {
msyslog(LOG_ERR, "invalid MAXPOLL value (%ld) in file %s",
intval[TOK_MAXPOLL], name);
#define CLOCK_LIMIT 30 /* poll-adjust threshold */
#define CLOCK_PGATE 4. /* poll-adjust gate */
#define PPS_MAXAGE 120 /* kernel pps signal timeout (s) */
+#define FREQTOD(x) ((x) / 65536e6) /* NTP to double */
+#define DTOFREQ(x) ((int32)((x) * 65536e6)) /* NTP to double */
/*
* Clock discipline state machine. This is used to control the
* timewarp.
*
* State < step > step Comments
- * ====================================================
- * NSET FREQ step, FREQ no ntp.drift
+ * ========================================================
+ * NSET FREQ step, FREQ no frequency set
*
- * FSET SYNC step, SYNC ntp.drift
+ * FSET SYNC step, SYNC frequency set
*
* FREQ if (mu < 900) if (mu < 900) set freq
* ignore ignore
* SPIK SYNC step, SYNC set phase
*/
#define S_NSET 0 /* clock never set */
-#define S_FSET 1 /* frequency set from the drift file */
+#define S_FSET 1 /* frequency set */
#define S_SPIK 2 /* spike detected */
#define S_FREQ 3 /* frequency mode */
#define S_SYNC 4 /* clock synchronized */
/*
* Kernel PLL/PPS state machine. This is used with the kernel PLL
- * modifications described in the README.kernel file.
+ * modifications described in the documentation.
*
* If kernel support for the ntp_adjtime() system call is available, the
* ntp_control flag is set. The ntp_enable and kern_enable flags can be
u_long pps_control; /* last pps update */
u_int sys_tai; /* TAI offset from UTC */
static void rstclock (int, double); /* transition function */
+static double direct_freq(double); /* direct set frequency */
#ifdef KERNEL_PLL
-struct timex ntv; /* kernel API parameters */
-int pll_status; /* status bits for kernel pll */
+static struct timex ntv; /* ntp_adjtime() parameters */
+int pll_status; /* last kernel status bits */
+#if defined(STA_NANO) && NTP_API == 4
+static u_int loop_tai; /* last TAI offset */
+#endif /* STA_NANO */
#endif /* KERNEL_PLL */
/*
* Clock state machine variables
*/
int state; /* clock discipline state */
-u_char sys_poll = NTP_MINPOLL; /* time constant/poll (log2 s) */
+u_char sys_poll = NTP_MINPOLL; /* time constant/poll (log2 s) */
int tc_counter; /* jiggle counter */
double last_offset; /* last offset (s) */
int clock_stepcnt; /* step counter */
init_loopfilter(void)
{
/*
- * Initialize state variables. Initially, we expect no drift
- * file, so set the state to S_NSET. If a drift file is present,
- * it will be detected later and the state set to S_FSET.
+ * Initialize state variables. Initially, we expect no frequency
+ * file, so set the state to S_NSET. If a frequency file is
+ * present, it will be detected later and the state set to
+ * S_FSET.
*/
rstclock(S_NSET, 0);
clock_jitter = LOGTOD(sys_precision);
{
int rval; /* return code */
int osys_poll; /* old system poll */
- double flladj; /* FLL frequency adjustment (ppm) */
- double plladj; /* PLL frequency adjustment (ppm) */
- double clock_frequency; /* clock frequency adjustment (ppm) */
+ double clock_frequency; /* clock frequency */
double dtemp, etemp; /* double temps */
/*
}
/*
- * If simulating ntpdate, set the clock directly, rather than
- * using the discipline. The clock_max defines the step
- * threshold, above which the clock will be stepped instead of
- * slewed. The value defaults to 128 ms, but can be set to even
- * unreasonable values. If set to zero, the clock will never be
- * stepped. Note that a slew will persist beyond the life of
- * this program.
- *
- * Note that if ntpdate is active, the terminal does not detach,
- * so the termination comments print directly to the console.
+ * This section simulates ntpdate. If the offset exceeds the
+ * step threshold (128 ms), step the clock to that time and
+ * exit. Othewise, slew the clock to that time and exit. Note
+ * that the slew will persist and eventually complete beyond the
+ * life of this program. Note that while ntpdate is active, the
+ * terminal does not detach, so the termination message prints
+ * directly to the terminal.
*/
if (mode_ntpdate) {
if (fabs(fp_offset) > clock_max && clock_max > 0) {
}
/*
- * Clock state machine transition function. This is where the
- * action is and defines how the system reacts to large phase
- * and frequency errors. There are two main regimes: when the
- * offset exceeds the step threshold and when it does not.
- * However, if the step threshold is set to zero, a step will
- * never occur. See the instruction manual for the details how
- * these actions interact with the command line options.
+ * Clock state machine transition function which defines how the
+ * system reacts to large phase and frequency excursion. There
+ * are two main regimes: when the offset exceeds the step
+ * threshold (128 ms) and when it does not. Under certain
+ * conditions updates are suspended until the stepout theshold
+ * (900 s) is exceeded. See the documentation on how these
+ * thresholds interact with commands and command line options.
*
* Note the kernel is disabled if step is disabled or greater
- * than 0.5 s.
+ * than 0.5 s or in ntpdate mode..
*/
osys_poll = sys_poll;
if (sys_poll < peer->minpoll)
if (sys_poll > peer->maxpoll)
sys_poll = peer->maxpoll;
clock_epoch += mu;
- clock_frequency = flladj = plladj = 0;
+ clock_frequency = drift_comp;
rval = 1;
if (fabs(fp_offset) > clock_max && clock_max > 0) {
switch (state) {
if (clock_epoch < clock_minstep)
return (0);
- clock_frequency = (fp_offset - clock_offset) /
- clock_epoch;
+ clock_frequency = direct_freq(fp_offset);
/* fall through to S_SPIK */
* from the frequency file. Since the time is outside
* the step threshold, the clock is stepped immediately,
* rather than after the stepout interval. Guys get
- * nervous if it takes 17 minutes to set the clock for
+ * nervous if it takes 15 minutes to set the clock for
* the first time.
*
* In S_FREQ and S_SPIK states the stepout threshold has
* expired and the phase is still above the step
* threshold. Note that a single spike greater than the
- * step threshold is always suppressed, even at the
- * longer poll intervals.
+ * step threshold is always suppressed, even with a
+ * long time constant.
*/
default:
step_systime(fp_offset);
/*
* In S_FREQ state ignore updates until the stepout
- * threshold. After that, correct the phase and
- * frequency and switch to S_SYNC state.
+ * threshold. After that, compute the new frequency, but
+ * do not adjust the phase or frequency until the next
+ * update.
*/
case S_FREQ:
if (clock_epoch < clock_minstep)
return (0);
- clock_frequency = (fp_offset - clock_offset) /
- clock_epoch;
- rstclock(S_SYNC, fp_offset);
+ clock_frequency = direct_freq(fp_offset);
+ rstclock(S_SYNC, 0);
break;
+
/*
* We get here by default in S_SYNC and S_SPIK states.
* Here we compute the frequency update due to PLL and
/*
* The FLL and PLL frequency gain constants
- * depend on the poll interval and Allan
+ * depend on the time constant and Allan
* intercept. The PLL is always used, but
* becomes ineffective above the Allan
* intercept. The FLL is not used below one-half
*/
if (sys_poll > allan_xpt - 1) {
dtemp = CLOCK_FLL - sys_poll;
- flladj = (fp_offset - clock_offset) /
- (max(clock_epoch, allan_xpt) *
- dtemp);
+ clock_frequency += (fp_offset -
+ last_offset) / (max(clock_epoch,
+ allan_xpt) * dtemp);
}
/*
* For the PLL the integration interval
* (numerator) is the minimum of the update
- * interval and poll interval. This allows
+ * interval and time constant. This allows
* oversampling, but not undersampling.
*/
etemp = min(clock_epoch,
(u_long)ULOGTOD(sys_poll));
dtemp = 4 * CLOCK_PLL * ULOGTOD(sys_poll);
- plladj = fp_offset * etemp / (dtemp * dtemp);
+ clock_frequency += fp_offset * etemp / (dtemp *
+ dtemp);
rstclock(S_SYNC, fp_offset);
break;
}
dtemp);
ntv.constant = sys_poll - 4;
#endif /* STA_NANO */
-
- /*
- * The frequency is set directly only if
- * clock_frequency is nonzero coming out of FREQ
- * state.
- */
- if (clock_frequency != 0) {
- ntv.modes |= MOD_FREQUENCY;
- ntv.freq = (int32)((clock_frequency +
- drift_comp) * 65536e6);
- }
ntv.esterror = (u_int32)(clock_jitter * 1e6);
ntv.maxerror = (u_int32)((sys_rootdelay / 2 +
sys_rootdisp) * 1e6);
ntv.status &= ~(STA_PPSFREQ |
STA_PPSTIME);
}
-
- /*
- * If less than 23 hours remain before a leap,
- * set the kernel leap bits.
- */
- if (leap_sec > 0 && leap_sec < 23 * 3600) {
- if (sys_leap == LEAP_ADDSECOND)
- ntv.status |= STA_INS;
- else if (sys_leap == LEAP_DELSECOND)
- ntv.status |= STA_DEL;
- }
+ if (sys_leap == LEAP_ADDSECOND)
+ ntv.status |= STA_INS;
+ else if (sys_leap == LEAP_DELSECOND)
+ ntv.status |= STA_DEL;
}
/*
* frequency and pretend we did it here.
*/
if (ntp_adjtime(&ntv) == TIME_ERROR) {
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_NOTICE,
- "kernel time sync error %04x", ntv.status);
ntv.status &= ~(STA_PPSFREQ | STA_PPSTIME);
+ msyslog(LOG_ERR,
+ "kernel time sync error %04x", ntv.status);
} else {
if ((ntv.status ^ pll_status) & ~STA_FLL)
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_NOTICE,
+ NLOG(NLOG_SYNCSTATUS)
+ msyslog(LOG_INFO,
"kernel time sync status change %04x",
ntv.status);
}
#else /* STA_NANO */
clock_offset = ntv.offset / 1e6;
#endif /* STA_NANO */
- clock_frequency = ntv.freq / 65536e6;
- flladj = plladj = 0;
+ clock_frequency = FREQTOD(ntv.freq);
/*
* If the kernel PPS is lit, monitor its performance.
clock_jitter = ntv.jitter / 1e6;
#endif /* STA_NANO */
}
- } else {
-#endif /* KERNEL_PLL */
-
+
+#if defined(STA_NANO) && NTP_API == 4
/*
- * We get here if the kernel discipline is not enabled.
- * Adjust the clock frequency as the sum of the directly
- * computed frequency (if measured) and the PLL and FLL
- * increments.
+ * If the TAI changes, update the kernel TAI.
*/
- clock_frequency = drift_comp + clock_frequency +
- flladj + plladj;
-#ifdef KERNEL_PLL
+ if (loop_tai != sys_tai) {
+ loop_tai = sys_tai;
+ ntv.modes = MOD_TAI;
+ ntv.constant = sys_tai;
+ ntp_adjtime(&ntv);
+ }
+#endif /* STA_NANO */
}
#endif /* KERNEL_PLL */
/*
* Clamp the frequency within the tolerance range and calculate
- * the frequency change since the last update.
+ * the frequency difference since the last update.
*/
if (fabs(clock_frequency) > NTP_MAXFREQ)
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_NOTICE,
+ msyslog(LOG_NOTICE,
"frequency error %.0f PPM exceeds tolerance %.0f PPM",
clock_frequency * 1e6, NTP_MAXFREQ * 1e6);
dtemp = SQUARE(clock_frequency - drift_comp);
drift_comp = clock_frequency;
/*
- * Calculate the wander as the exponentially weighted frequency
- * differences. Enable the frequency file to be written.
+ * Calculate the wander as the exponentially weighted RMS
+ * frequency differences. Record the change for the frequency
+ * file update.
*/
etemp = SQUARE(clock_stability);
clock_stability = SQRT(etemp + (dtemp - etemp) / CLOCK_AVG);
drift_file_sw = TRUE;
/*
- * Here we adjust the poll interval by comparing the current
+ * Here we adjust the timeconstan by comparing the current
* offset with the clock jitter. If the offset is less than the
* clock jitter times a constant, then the averaging interval is
* increased, otherwise it is decreased. A bit of hysteresis
}
/*
- * If the poll interval has changed, update the poll variables.
+ * If the time constant has changed, update the poll variables.
*/
if (osys_poll != sys_poll)
poll_update(peer, sys_poll);
record_loop_stats(clock_offset, drift_comp, clock_jitter,
clock_stability, sys_poll);
#ifdef DEBUG
- if (debug > 1)
+ if (debug)
printf(
- "local_clock: jitr %.6f freq %.3f stab %.6f thres %.6f\n",
- clock_jitter, drift_comp * 1e6, clock_stability *
- 1e6, wander_threshold * 1e6);
+ "local_clock: offset %.9f jitr %.6f freq %.3f stab %.6f poll %d\n",
+ clock_offset, clock_jitter, drift_comp * 1e6,
+ clock_stability * 1e6, sys_poll);
#endif /* DEBUG */
return (rval);
#endif /* LOCKCLOCK */
*/
if (pps_control && current_time - pps_control > PPS_MAXAGE) {
if (pps_control)
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_NOTICE, "pps sync disabled");
+ NLOG(NLOG_SYNCSTATUS)
+ msyslog(LOG_INFO, "pps sync disabled");
pps_control = 0;
}
* Implement the phase and frequency adjustments. The gain
* factor (denominator) is not allowed to increase beyond the
* Allan intercept. It doesn't make sense to average phase noise
- * beyond this point and it helps to damp residual offset at the
- * longer poll intervals.
+ * beyond this point and it helps to damp residual offset with a
+ * longer time constant.
*/
adjustment = clock_offset / (CLOCK_PLL * ULOGTOD(min(sys_poll,
allan_xpt)));
/*
- * Clock state machine. Enter new state and set state variables. Note we
- * use the time of the last clock filter sample, which may be earlier
- * than the current time.
+ * Clock state machine. Enter new state and set state variables.
*/
static void
rstclock(
)
{
#ifdef DEBUG
- if (debug)
- printf("local_clock: intvl %lu offset %.6f freq %.3f state %d poll %d count %d\n",
+ if (debug > 1)
+ printf("local_clock: mu %lu offset %.6f freq %.3f state %d poll %d count %d\n",
clock_epoch, offset, drift_comp * 1e6, trans,
sys_poll, tc_counter);
#endif
clock_epoch = 0;
}
+/*
+ * calc_freq - calculate frequency directly
+ *
+ * This is very carefully done. When the offset is first computed at the
+ * first update, a residual frequency component results. Subsequently,
+ * updates are suppresed until the end of the measurement interval while
+ * the offset is amortized. At the end of the interval the frequency is
+ * calculated from the current offset, residual offset, length of the
+ * interval and residual frequency component.
+ */
+static double direct_freq(
+ double fp_offset
+ )
+{
+#ifdef KERNEL_PLL
+ double freq = 0;
+
+ /*
+ * If the kernel is enabled, we need the residual offset and
+ * frequency to calculate the frequency correction.
+ */
+ if (pll_control && kern_enable) {
+ memset(&ntv, 0, sizeof(ntv));
+ ntp_adjtime(&ntv);
+#ifdef STA_NANO
+ clock_offset = ntv.offset / 1e9;
+#else /* STA_NANO */
+ clock_offset = ntv.offset / 1e6;
+#endif /* STA_NANO */
+ freq = (fp_offset - clock_offset) / clock_epoch +
+ FREQTOD(ntv.freq);
+ if (freq != 0) {
+ ntv.modes = MOD_FREQUENCY;
+ ntv.freq = DTOFREQ(freq);
+ ntp_adjtime(&ntv);
+ msyslog(LOG_NOTICE,
+ "kernel frequency set %.3f PPM", freq *
+ 1e6);
+ ntp_adjtime(&ntv);
+ }
+ return (freq);
+ } else {
+ return ((fp_offset - clock_offset) / clock_epoch +
+ drift_comp);
+ }
+#else /* KERNEL_PLL */
+ return ((fp_offset - clock_offset) / clock_epoch + drift_comp);
+#endif /* KERNEL_PLL */
+
+}
+
/*
* huff-n'-puff filter
#endif
switch (item) {
+ /*
+ * We first assume the kernel supports the ntp_adjtime()
+ * syscall. If that syscall works, initialize the kernel time
+ * variables. Otherwise, continue leaving no harm behind.
+ */
case LOOP_DRIFTINIT:
-
#ifndef LOCKCLOCK
#ifdef KERNEL_PLL
- /*
- * Assume the kernel supports the ntp_adjtime() syscall.
- * If that syscall works, initialize the kernel time
- * variables. Otherwise, continue leaving no harm
- * behind. While at it, ask to set nanosecond mode. If
- * the kernel agrees, rejoice; othewise, it does only
- * microseconds.
- */
if (mode_ntpdate)
break;
pll_control = 1;
memset(&ntv, 0, sizeof(ntv));
-#ifdef STA_NANO
- ntv.modes = MOD_BITS | MOD_NANO;
-#else /* STA_NANO */
- ntv.modes = MOD_BITS;
-#endif /* STA_NANO */
+ ntv.modes = MOD_BITS | MOD_FREQUENCY;
+ ntv.status = STA_PLL;
ntv.maxerror = MAXDISPERSE;
ntv.esterror = MAXDISPERSE;
- ntv.status = STA_UNSYNC;
#ifdef SIGSYS
/*
* Use sigsetjmp() to save state and then call
if (pll_status & STA_CLK)
ext_enable = 1;
#endif /* STA_NANO */
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_INFO,
- "kernel time sync status %04x",
- pll_status);
+ msyslog(LOG_NOTICE,
+ "kernel time sync enabled %04x",
+ ntv.status);
}
#endif /* KERNEL_PLL */
#endif /* LOCKCLOCK */
break;
+ /*
+ * Initialize the frequency. If the frequency file is missing or
+ * broken, set the initial frequency to zero. The state remains
+ * S_NSET. Otherwise, set the initial frequency to the given
+ * value and the state to S_FSET.
+ */
case LOOP_DRIFTCOMP:
-
#ifndef LOCKCLOCK
- /*
- * If the frequency value is reasonable, set the initial
- * frequency to the given value and the state to S_FSET.
- * Otherwise, the drift file may be missing or broken,
- * so set the frequency to zero. This erases past
- * history should somebody break something.
- */
- if (freq <= NTP_MAXFREQ && freq >= -NTP_MAXFREQ) {
- drift_comp = freq;
- rstclock(S_FSET, 0);
- } else {
+ if (freq > NTP_MAXFREQ || freq < -NTP_MAXFREQ) {
drift_comp = 0;
+ break;
}
+ drift_comp = freq;
+ rstclock(S_FSET, 0);
#ifdef KERNEL_PLL
/*
- * Sanity check. If the kernel is available, load the
- * frequency and light up the loop. Make sure the offset
- * is zero to cancel any previous nonsense. If you don't
- * want this initialization, remove the ntp.drift file.
+ * If the kernel is enabled, load the frequency.
*/
if (pll_control && kern_enable) {
memset((char *)&ntv, 0, sizeof(ntv));
- ntv.modes = MOD_OFFSET | MOD_FREQUENCY;
- ntv.freq = (int32)(drift_comp * 65536e6);
+ ntv.freq = DTOFREQ(drift_comp);
+ ntv.modes = MOD_FREQUENCY;
ntp_adjtime(&ntv);
}
#endif /* KERNEL_PLL */
#endif /* LOCKCLOCK */
break;
+ /*
+ * Disable the kernel at shutdown. The microkernel just abandons
+ * ship. The nanokernel carefully cleans up so applications can
+ * see this. Note the last programmed offset and frequency are
+ * left in place.
+ */
case LOOP_KERN_CLEAR:
#ifndef LOCKCLOCK
#ifdef KERNEL_PLL
- /* Completely turn off the kernel time adjustments. */
- if (pll_control) {
+ if (pll_control && kern_enable) {
memset((char *)&ntv, 0, sizeof(ntv));
- ntv.modes = MOD_BITS | MOD_OFFSET | MOD_FREQUENCY;
- ntv.status = STA_UNSYNC;
+ ntv.modes = MOD_STATUS;
+ ntv.status = 0;
ntp_adjtime(&ntv);
- NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT)
- msyslog(LOG_INFO,
+ msyslog(LOG_NOTICE,
"kernel time sync disabled %04x",
ntv.status);
}
#endif /* LOCKCLOCK */
break;
- case LOOP_LEAP: /* set kernel TAI offset */
-#if defined(STA_NANO) && NTP_API == 4
- if (pll_control && kern_enable) {
- ntv.modes = MOD_TAI;
- ntv.constant = sys_tai;
- ntp_adjtime(&ntv);
- }
-#endif /* STA_NANO */
- break;
-
/*
- * tinker command variables for Ulrich Windl. Very dangerous.
+ * Tinker command variables for Ulrich Windl. Very dangerous.
*/
case LOOP_ALLAN: /* Allan intercept (log2) (allan) */
allan_xpt = (u_char)freq;
clock_minstep = freq;
break;
+ case LOOP_LEAP: /* not used */
default:
- msyslog(LOG_INFO,
+ msyslog(LOG_NOTICE,
"loop_config: unsupported option %d", item);
}
}
* packet will be discarded if the interval betweem packets is less than
* 1 s, as well as when the average interval is less than 16 s.
*/
-int res_avg_interval = 1 << NTP_MINPOLL; /* avg interpkt interval */
+int ntp_minpoll = NTP_MINPOLL; /* avg interpkt interval */
int res_min_interval = 1 << NTP_MINPKT; /* min interpkt interval */
/*
md->leak -= interval;
if (md->leak < 0)
md->leak = 0;
- leak = md->leak + res_avg_interval;
+ leak = md->leak + (1 << ntp_minpoll);
#ifdef DEBUG
if (debug > 1)
- printf("restrict: min %d average %d\n",
+ printf("restrict: interval %d headway %d\n",
interval, leak);
#endif
if (interval >= res_min_interval - 1 && leak <
- NTP_SHIFT * res_avg_interval + 2) {
+ NTP_SHIFT * (1 << ntp_minpoll) + 2) {
md->leak = leak;
md->flags &= ~RES_LIMITED;
}
/*
* This routine is called about once per day from the timer
* routine and when the client is first synchronized. Search the
- * peer list for all associations and flush the key list. Also, * fetch the leap second values.
+ * peer list for all associations.
*/
if (!crypto_flags)
return;
for (n = 0; n < NTP_HASH_SIZE; n++) {
for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
- peer->crypto &= ~CRYPTO_FLAG_LEAP;
next_peer = peer->next;
if (!(peer->flags & FLAG_SKEY)) {
continue;
static int sys_hopper; /* anticlockhop counter */
static int sys_maxhop = MAXHOP; /* anticlockhop counter threshold */
int leap_tai; /* TAI at next next leap */
-u_long leap_sec; /* next leap */
-u_long leap_expire; /* leapfile expiration */
-static int leap_next; /* leap consensus */
+u_long leap_sec; /* next scheduled leap from file */
+u_long leap_peers; /* next scheduled leap from peers */
+u_long leap_expire; /* leap information expiration */
+static int leap_vote; /* leap consensus */
keyid_t sys_private; /* private value for session seed */
int sys_manycastserver; /* respond to manycast client pkts */
int peer_ntpdate; /* active peers in ntpdate mode */
u_long sys_oldversion; /* old version */
u_long sys_restricted; /* access denied */
-u_long sys_badlength; /* bad length or format */
+u_long sys_badlength; /* bad version, length or format */
u_long sys_badauth; /* bad authentication */
u_long sys_declined; /* packets declined */
u_long sys_limitrejected; /* rate exceeded */
*/
if (peer->unreach >= NTP_UNREACH) {
if (peer->flags & FLAG_PREEMPT &&
- sys_survivors >= sys_maxclock) {
+ (sys_survivors > sys_maxclock ||
+ peer->pmode == MODE_BROADCAST)) {
peer_clear(peer, "TIME");
unpeer(peer);
return;
* If timeout in Autokey dance, restart
* the protocol.
*/
- if (peer->crypto) {
+ if (peer->crypto || (peer->flash &
+ TEST9)) {
peer_clear(peer, "TIME");
peer->unreach = 0;
}
process_control(rbufp, restrict_mask);
return;
}
- if (restrict_mask & RES_DONTSERVE) {
- sys_restricted++;
- return; /* no time */
- }
- if (rbufp->recv_length < LEN_PKT_NOMAC) {
- sys_badlength++;
- return; /* runt packet */
- }
/*
* Version check must be after the query packets, since they
}
}
+ /*
+ * If access denied or rate exceeded and no KoD, don't waste
+ * further cycles.
+ */
+ if (restrict_mask & RES_DONTSERVE)
+ sys_restricted++;
+ if (restrict_mask & RES_LIMITED)
+ sys_limitrejected++;
+ if (restrict_mask & (RES_DONTSERVE | RES_LIMITED) &&
+ !(restrict_mask & RES_DEMOBILIZE))
+ return;
+
/*
* Parse the extension field if present. We figure out whether
* an extension field is present by measuring the MAC size. If
*/
authlen = LEN_PKT_NOMAC;
has_mac = rbufp->recv_length - authlen;
- while (has_mac > 0) {
+ while (has_mac != 0) {
int temp;
if (has_mac % 4 != 0 || has_mac < 0) {
sys_badlength++;
- return; /* bad MAC length */
+ return; /* bad length */
}
if (has_mac == 1 * 4 || has_mac == 3 * 4 || has_mac ==
MAX_MAC_LEN) {
} else if (has_mac > MAX_MAC_LEN) {
temp = ntohl(((u_int32 *)pkt)[authlen / 4]) &
0xffff;
- if (temp < 4 || temp > NTP_MAXEXTEN || temp % 4
- != 0) {
+ if (temp < 4 || temp % 4 != 0 || temp +
+ authlen + MAX_MAC_LEN >
+ rbufp->recv_length) {
sys_badlength++;
- return; /* bad MAC length */
+ return; /* bad length */
}
+
+ /*
+ * Extension fields are illegal if Autokey is
+ * not configured.
+ */
+#ifdef OPENSSL
+ if (!crypto_flags)
+ restrict_mask |= RES_DONTSERVE;
+#elif /* OPENSSL */
+ restrict_mask |= RES_DONTSERVE;
+#endif /* OPENSSL */
authlen += temp;
has_mac -= temp;
} else {
sys_badlength++;
- return; /* bad MAC length */
+ return; /* bad length */
}
}
#ifdef OPENSSL
/*
* We have tossed out as many buggy packets as possible early in
- * the game to reduce the exposure to a clogging attack. Now we
+ * the game to reduce the exposure to a clogging attack. now we
* have to burn some cycles to find the association and
* authenticate the packet if required. Note that we burn only
* MD5 cycles, again to reduce exposure. There may be no
/*
* The vanilla case is when this is not a multicast
- * interface. If authentication succeeds, return a
- * server mode packet; if not and the key ID is nonzero,
- * return a crypto-NAK.
+ * interface. If a restrict bit is lit, drop the packet.
+ * If directed, send a KoD.
*/
- if (restrict_mask & RES_LIMITED) {
- sys_limitrejected++;
- if (restrict_mask & RES_DEMOBILIZE)
- fast_xmit(rbufp, hismode, skeyid,
- "RATE");
- return;
+ if (restrict_mask & RES_DONTSERVE) {
+ fast_xmit(rbufp, hismode, skeyid, "DENY");
+ return; /* access denied */
+
+ } else if (restrict_mask & RES_LIMITED) {
+ fast_xmit(rbufp, hismode, skeyid, "RATE");
+ return; /* rate exceeded */
}
+
+ /*
+ * If authentication OK, send a server reply; otherwise,
+ * send a crypto-NAK.
+ */
if (!(rbufp->dstadr->flags & INT_MCASTOPEN)) {
if (AUTH(restrict_mask & RES_DONTTRUST,
is_authentic))
*/
if (AUTH(restrict_mask & RES_DONTTRUST, is_authentic))
fast_xmit(rbufp, hismode, skeyid, NULL);
-
return; /* hooray */
/*
* neither is Autokey.
*/
if (skeyid > NTP_MAXKEY) {
- msyslog(LOG_INFO,
+ msyslog(LOG_NOTICE,
"receive: autokey requires two-way communication");
sys_restricted++;
return; /* no autokey */
/*
* Test for kiss-o'death packet. We carefully avoid a hazard
- * when a terrorist broadcaster kisses the frog.
+ * when the client has restarted the association after a kiss by
+ * upping the throttle to the max.
*/
if (hismode == MODE_SERVER && hisleap == LEAP_NOTINSYNC &&
hisstratum == STRATUM_UNSPEC) {
- if (memcmp(&pkt->refid, "RATE", 4) == 0) {
- peer_clear(peer, "RATE");
- peer->flash |= TEST4; /* rate quench */
- msyslog(LOG_INFO,
+ if (memcmp(&pkt->refid, "DENY", 4) == 0) {
+ peer_clear(peer, "DENY");
+ peer->flash |= TEST4;
+ msyslog(LOG_NOTICE,
+ "receive: server %s access denied",
+ stoa(&rbufp->recv_srcadr));
+ } else if (memcmp(&pkt->refid, "RATE", 4) == 0) {
+ peer->throttle += NTP_SHIFT * (1 <<
+ ntp_minpoll);
+ poll_update(peer, peer->hpoll);
+ msyslog(LOG_NOTICE,
"receive: server %s maximum rate exceeded",
stoa(&rbufp->recv_srcadr));
- return;
}
}
peer->flash |= TEST8; /* not proventic */
/*
- * If the transmit queue is nonempty, clamp the host
- * poll interval to the packet poll interval.
+ * About once a week restart the Autokey protocol to
+ * slurp up and refreshed certificates or leapsecond
+ * values.
*/
- if (peer->cmmd != 0) {
- peer->ppoll = pkt->ppoll;
- poll_update(peer, peer->hpoll);
+ if (current_time > peer->refresh) {
+ peer_clear(peer, "CRYP");
+ return;
}
}
#endif /* OPENSSL */
pstratum = PKT_TO_STRATUM(pkt->stratum);
/*
- * Capture the header values.
+ * Capture the header values in the client/peer association..
*/
record_raw_stats(&peer->srcadr, peer->dstadr ?
&peer->dstadr->sin : NULL, &p_org, &p_rec, &p_xmt,
peer->refid = pkt->refid; /* network byte order */
peer->reftime = p_reftime;
+ /*
+ * First, if either burst mode is armed, enable the burst.
+ * Compute the headway for the next packet and delay if
+ * necessary to avoid exceeding the threshold.
+ */
+ if (peer->retry > 0) {
+ peer->retry = 0;
+ if (peer->reach)
+ peer->burst = min(1 << (peer->hpoll -
+ ntp_minpoll), NTP_SHIFT) - 1;
+ else
+ peer->burst = NTP_IBURST - 1;
+ peer->nextdate = current_time;
+ }
+ poll_update(peer, peer->hpoll);
+
/*
* Verify the server is synchronized; that is, the leap bits and
* stratum are valid, the root delay and root dispersion are
}
/*
- * If the peer was previously unreachable, raise a trap. If a
- * burst mode is active, initialize the burst. The unreachable
- * burst is always NTP_IBURST (6) packets; the reachable burst
- * is tailored not to exceed the minimum average headway of 16
- * s.
+ * If the peer was previously unreachable, raise a trap. In any
+ * case, mark it reachable.
*/
if (!peer->reach) {
report_event(EVNT_REACH, peer);
peer->timereachable = current_time;
- if (peer->retry > 0) {
- peer->retry = 0;
- peer->burst = NTP_IBURST - 1;
- peer->nextdate = peer->outdate +
- res_min_interval;
- }
- } else {
- if (peer->retry > 0) {
- peer->retry = 0;
- peer->burst = min(1 << (peer->hpoll -
- NTP_MINPOLL), NTP_SHIFT) - 1;
- if (peer->burst > 0)
- peer->nextdate = peer->outdate +
- res_min_interval;
- }
}
peer->reach |= 1;
- poll_update(peer, peer->hpoll);
/*
* For a client/server association, calculate the clock offset,
* only half that span. Since the typical first-order
* differences are usually very small, they are converted to 64-
* bit doubles and all remaining calculations done in floating-
- * point arithmetic. This preserves the accuracy while retaining
- * the 68-year span.
+ * double arithmetic. This preserves the accuracy while
+ * retaining the 68-year span.
*
* Let t1 = p_org, t2 = p_rec, t3 = p_xmt, t4 = peer->rec:
*/
.5) * p_del;
else
td = 0;
+
+ /*
+ * Unfortunately, in many cases the errors are
+ * unacceptable, so for the present the rates are not
+ * used. In future, we might find conditions where the
+ * calculations are useful, so this should be considered
+ * a work in progress.
+ */
#if 0 /* temporarily disabled */
t21 -= td;
t34 -= td;
{
u_char ostratum;
double dtemp;
- l_fp now;
u_long epoch;
+ l_fp now;
#ifdef HAVE_LIBSCF_H
char *fmri;
#endif /* HAVE_LIBSCF_H */
sys_reftime = peer->rec;
/*
- * If a leapseconds file is not present and the number
- * of survivor leap bits is greater than half the number
- * of survivors, schedule a leap for the end of the
- * current month.
+ * If the leapseconds values are from file or network
+ * and the leap is in the future, schedule a leap at the
+ * given epoch. Otherwise, if the number of survivor
+ * leap bits is greater than half the number of
+ * survivors, schedule a leap for the end of the current
+ * month.
*/
get_systime(&now);
- if (leap_expire == 0) {
- u_long leapsec;
-
- leapsec = leap_month(now.l_ui);
- if (leapsec < 28 * 86400) {
- leapsec += now.l_ui;
- if (leapsec != leap_sec) {
- leap_sec = leapsec;
+ if (leap_sec > 0) {
+ if (leap_sec > now.l_ui) {
+ sys_tai = leap_tai - 1;
+ if (leapsec == 0)
+ leapsec = leap_sec - now.l_ui;
msyslog(LOG_NOTICE,
- "proto: leap epoch %lu", leap_sec);
+ "crypto: leap epoch %.1f days",
+ leapsec / 86400.);
}
} else {
- leap_sec = 0;
+ sys_tai = leap_tai;
}
+ break;
+
+ 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)
+ leapsec = leap_peers - now.l_ui;
+ msyslog(LOG_NOTICE,
+ "proto: leap epoch %.1f days",
+ leapsec / 86400.);
+ }
+ } else {
+ leapsec = 0;
}
break;
/*
)
{
int hpoll;
+ u_long next, utemp;
/*
* This routine figures out when the next poll should be sent.
peer->hpoll = hpoll;
/*
- * Now we figure out if there is an override. If during the
- * crypto protocol and a responce message is pending, delay one
- * second.
- */
-#ifdef OPENSSL
- if (peer->cmmd != NULL && (sys_leap != LEAP_NOTINSYNC ||
- peer->crypto)) {
- peer->nextdate = current_time + RESP_DELAY;
-
- /*
- * If we get called from the receive routine while a burst is
- * pending, just slink away. If a reference clock, delay one
- * second; otherwise, delay two seconds.
+ * There are three variables important for poll scheduling, the
+ * current time (current_time), next scheduled time (nextdate)
+ * and the earliest time (utemp). The earliest time is 2 s
+ * seconds, but could be more due to rate management. When
+ * sending in a burst, use the earliest time. When not in a
+ * burst but with a reply pending, send at the earliest time
+ * unless the next scheduled time has not advanced. This can
+ * only happen if multiple replies are peinding in the same
+ * response interval. Otherwise, send at the later of the next
+ * scheduled time and the earliest time.
+ *
+ * Now we figure out if there is an override. If a burst is in
+ * progress and we get called from the receive process, just
+ * slink away. If called from the poll process, delay 1 s for a
+ * reference clock, otherwise 2 s.
*/
- } else if (peer->burst > 0) {
-#else /* OPENSSL */
+ utemp = current_time + max(peer->throttle - (NTP_SHIFT - 1) *
+ (1 << ntp_minpoll), res_min_interval);
if (peer->burst > 0) {
-#endif /* OPENSSL */
- if (peer->nextdate != current_time)
+ if (peer->nextdate > current_time)
return;
#ifdef REFCLOCK
else if (peer->flags & FLAG_REFCLOCK)
- peer->nextdate += RESP_DELAY;
+ peer->nextdate = current_time + RESP_DELAY;
#endif /* REFCLOCK */
else
- peer->nextdate += res_min_interval;
+ peer->nextdate = utemp;
+
+ /*
+ * If a burst is not in progress and a crypto response message
+ * is pending, delay 2 s, but only if this is a new interval..
+ */
+ } else if (peer->cmmd != NULL) {
+ if (peer->nextdate > current_time) {
+ if (peer->nextdate + res_min_interval != utemp)
+ peer->nextdate = utemp;
+ } else {
+ peer->nextdate = utemp;
+ }
/*
- * The ordinary case. If a retry, use minpoll; otherwise use the
- * minimum of the host and peer intervals. In other words,
- * oversampling is okay but understampling is evil.
+ * The ordinary case. If a retry, start wotj minpoll; otherwise
+ * wtart with the minimum of the host and peer intervals. In
+ * other words, oversampling is okay but understampling is evil.
+ * Use the maximum of this value and the headway, then increase
+ * by the minimum interval if the average headway is greater
+ * than 16 s. This is to reduce the average headway at the
+ * minimum poll interval of 16 s.
*/
} else {
if (peer->retry > 0)
hpoll = peer->minpoll;
else
hpoll = min(peer->ppoll, peer->hpoll);
- peer->nextdate = peer->outdate + RANDPOLL(hpoll);
- }
- /*
- * If the time for the next poll has already happened, bring it
- * up to the next second after this one. This way the only way
- * to get nexdate == current time is from the poll routine.
- */
- if (peer->nextdate <= current_time)
- peer->nextdate = current_time + 1;
+ next = (u_long)(0x10000 | (ntp_random() & 0x0fff)) << hpoll;
+
+printf("xxx %d, %d %d %lx\n", peer->ppoll, peer->hpoll, hpoll, next);\v
+ next = (u_long)((0x10000 | (ntp_random() & 0x0fff)) <<
+ hpoll) >> 16;
+ next += peer->outdate;
+ if (next > utemp)
+ peer->nextdate = next;
+ else
+ peer->nextdate = utemp;
+ if (peer->throttle > (1 << ntp_minpoll))
+ peer->nextdate += res_min_interval;
+ }
#ifdef DEBUG
if (debug > 1)
- printf("poll_update: at %lu %s flags %04x poll %d burst %d retry %d next %lu\n",
- current_time, ntoa(&peer->srcadr), peer->flags,
- peer->hpoll, peer->burst, peer->retry,
- peer->nextdate);
+ 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
}
/*
* During initialization use the association count to spread out
- * the polls at one-second intervals. Othersie, randomize over
+ * the polls at one-second intervals. Otherwise, randomize over
* the minimum poll interval in order to avoid broadcast
* implosion.
*/
if (initializing)
peer->nextdate += peer_associations;
else if (peer->hmode == MODE_PASSIVE)
- peer->nextdate += RESP_DELAY;
+ peer->nextdate += res_min_interval;
else
peer->nextdate += ntp_random() % peer_associations;
#ifdef OPENSSL
+ peer->refresh = current_time + NTP_REFRESH;
sprintf(statstr, "clear %d ident %s", peer->associd,
ident);
record_crypto_stats(&peer->srcadr, statstr);
nlist = 1;
} else {
if (osys_peer != NULL) {
- NLOG(NLOG_SYNCSTATUS)
- msyslog(LOG_INFO,
+ msyslog(LOG_NOTICE,
"no servers reachable");
report_event(EVNT_PEERSTCHG, NULL);
}
* the system peer, although all survivors are eligible for the
* combining algorithm. Check for prefer and pps peers at any
* stratum. Note that the head of the list is at the lowest
- * stratum and that unsynchronized peers cannot survivethis far.
+ * stratum and that unsynchronized peers cannot survive this
+ * far.
+ *
+ * Also, reset the association unreach timer for the first
+ * sys_maxclock survivors. The rest, if preemptable, will be
+ * kicked off the bus after timeout.
*
* While at it, count the number of leap warning bits found.
* This will be used later to vote the system leap warning bit.
* If a leap warning bit is found on a reference clock, the vote
* is always won.
*/
- leap_next = 0;
+ leap_vote = 0;
for (i = 0; i < nlist; i++) {
sys_survivors++;
peer = peer_list[i];
- if (i < sys_maxclock)
+ if (sys_survivors <= sys_maxclock)
peer->unreach = 0;
if (peer->leap == LEAP_ADDSECOND) {
if (peer->flags & FLAG_REFCLOCK)
- leap_next = nlist;
+ leap_vote = nlist;
else
- leap_next++;
+ leap_vote++;
}
peer->status = CTL_PST_SEL_SYNCCAND;
if (peer->flags & FLAG_PREFER)
sys_peer->status = CTL_PST_SEL_PPS;
sys_offset = sys_peer->offset;
if (!pps_control)
- NLOG(NLOG_SYSEVENT)
- msyslog(LOG_INFO,
+ NLOG(NLOG_SYNCSTATUS)
+ msyslog(LOG_INFO,
"pps sync enabled");
pps_control = current_time;
#ifdef DEBUG
#endif /* REFCLOCK */
src = ntoa(&sys_peer->srcadr);
NLOG(NLOG_SYNCSTATUS)
- msyslog(LOG_INFO, "synchronized to %s, stratum %d",
- src, sys_peer->stratum);
+ msyslog(LOG_INFO, "synchronized to %s, stratum %d",
+ src, sys_peer->stratum);
}
clock_update(sys_peer);
}
sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl],
&xpkt, sendlen);
peer->sent++;
- peer->throttle += res_avg_interval;
+ peer->throttle += 1 << ntp_minpoll;
#ifdef DEBUG
if (debug)
printf("transmit: at %ld %s->%s mode %d len %d\n",
/*
* In symmetric modes the digest, certificate, agreement
* parameters, cookie and autokey values are required.
- * The leapsecond table is optional. But, a passive peer
+ * The leapsecond field is optional. But, a passive peer
* will not believe the active peer until the latter has
* synchronized, so the agreement must be postponed
* until then. In any case, if a new keylist is
peer->associd, NULL);
/*
- * Postamble. We trade leapseconds only when the
- * server and client are synchronized.
+ * Postamble. We trade leapsecond fields only
+ * when the server and client are synchronized.
*/
else if (sys_leap != LEAP_NOTINSYNC &&
peer->leap != LEAP_NOTINSYNC &&
/*
* In client mode the digest, certificate, agreement
* parameters and cookie are required. The leapsecond
- * table is optional. If broadcast client mode, the
+ * field is optional. If broadcast client mode, the
* autokey values are required as well. In broadcast
* client mode, these values must be acquired during the
* client/server exchange to avoid having to wait until
HTONL_FP(&peer->xmt, &xpkt.xmt);
authlen = authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen);
if (authlen == 0) {
- msyslog(LOG_INFO, "transmit: %s key %u not found",
+ msyslog(LOG_NOTICE, "transmit: %s key %u not found",
stoa(&peer->srcadr), xkeyid);
peer->flash |= TEST9; /* no key found */
return;
sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl], &xpkt,
sendlen);
peer->sent++;
- peer->throttle += res_avg_interval;
+ peer->throttle += 1 << ntp_minpoll;
/*
* Calculate the encryption delay. Keep the minimum over
xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC,
PKT_VERSION(rpkt->li_vn_mode), xmode);
xpkt.stratum = STRATUM_PKT_UNSPEC;
- memcpy(&xpkt.refid, "RATE", 4);
+ memcpy(&xpkt.refid, mask, 4);
xpkt.org = rpkt->xmt;
xpkt.rec = rpkt->xmt;
xpkt.xmt = rpkt->xmt;
/*
* Find the nearest power of two.
*/
- NLOG(NLOG_SYSEVENT)
- msyslog(LOG_INFO, "precision = %.3f usec", tick * 1e6);
+ msyslog(LOG_NOTICE, "precision = %.3f usec", tick * 1e6);
for (i = 0; tick <= 1; i++)
tick *= 2;
if (tick - 1. > 1. - tick / 2)
break;
default:
- msyslog(LOG_INFO,
+ msyslog(LOG_NOTICE,
"proto_config: unsupported option %d", item);
}
}
/*
* The counters and timeouts
*/
+static u_long interface_timer; /* interface update timer */
static u_long adjust_timer; /* second timer */
static u_long stats_timer; /* stats timer */
static u_long huffpuff_timer; /* huff-n'-puff timer */
-static u_long interface_timer; /* interface update timer */
+u_long leapsec; /* leapseconds countdown */
#ifdef OPENSSL
static u_long revoke_timer; /* keys revoke timer */
u_long sys_revoke = KEY_REVOKE; /* keys revoke timeout */
{
register struct peer *peer, *next_peer;
u_int n;
- l_fp now;
/*
* The basic timerevent is one second. This is used to adjust
*/
if (peer->throttle > 0)
peer->throttle--;
- if (peer->nextdate <= current_time &&
- (peer->throttle == 0 || peer->burst > 0)) {
+ if (peer->nextdate <= current_time) {
#ifdef REFCLOCK
if (peer->flags & FLAG_REFCLOCK)
refclock_transmit(peer);
}
/*
- * Leapseconds. When the time remaining decrements to zero,
- * increment the TAI offset. If the kernel code is not available
- * or disabled, Do the leap crudely. There are of course races
- * here, cheerfully ignored.
+ * Leapseconds. If a leap is pending, decrement the time
+ * remaining. If less than one day remains, set the leap bits.
+ * When no time remains, clear the leap bits and increment the
+ * TAI. If kernel suppport is not available, do the leap
+ * crudely. Note a leap cannot be pending unless the clock is
+ * set.
*/
- if (leap_sec > 0) {
- get_systime(&now);
- if (now.l_ui > leap_sec) {
+ if (leapsec > 0) {
+ leapsec--;
+ if (leap_sec == 0) {
sys_leap = LEAP_NOWARNING;
sys_tai = leap_tai;
- } else if (now.l_ui - leap_sec < 28 * 86400) {
- sys_leap = LEAP_ADDSECOND;
- if (leap_tai > 0)
- sys_tai = leap_tai - 1;
- }
-#ifdef KERNEL_PLL
- if (now.l_ui - leap_sec == 600) {
- if (pll_control && kern_enable)
- loop_config(LOOP_LEAP, 0);
- }
-#endif /* KERNEL_PLL */
- if (leap_sec == 0) {
#ifdef KERNEL_PLL
if (!(pll_control && kern_enable))
step_systime(-1.0);
#else /* KERNEL_PLL */
- step_systime(-1.0);
+ step_systime(-1.0);
#endif /* KERNEL_PLL */
msyslog(LOG_NOTICE,
- "timer: leap second %lu TAI %d",
- leap_sec, sys_tai);
+ "leapsecond event %lu TAI %d",
+ current_time, sys_tai);
+ } else {
+ if (leapsec < DAY)
+ sys_leap = LEAP_ADDSECOND;
+ if (leap_tai > 0)
+ sys_tai = leap_tai - 1;
}
}
}
/*
- * Finally, write stats once per hour.
+ * Finally, write hourly stats.
*/
if (stats_timer <= current_time) {
stats_timer += HOUR;
/*
* Static prototypes
*/
-static void leap_file(char *);
+static int leap_file(FILE *);
/*
* init_util - initialize the utilities
void
init_util(void)
{
- stats_drift_file = 0;
- stats_temp_file = 0;
- key_file_name = 0;
+ stats_drift_file = NULL;
+ stats_temp_file = NULL;
+ key_file_name = NULL;
filegen_register(&statsdir[0], "peerstats", &peerstats);
filegen_register(&statsdir[0], "loopstats", &loopstats);
filegen_register(&statsdir[0], "clockstats", &clockstats);
#ifdef DEBUG_TIMING
filegen_register(&statsdir[0], "timingstats", &timingstats);
#endif /* DEBUG_TIMING */
-
-leap_file("/etc/ntp.leap"); /***** temp for debug *****/
-
}
setpriority(PRIO_PROCESS, 0, o_prio); /* downshift */
#endif /* VMS */
#endif /* DOSYNCTODR */
-
- NLOG(NLOG_SYSSTATIST)
- msyslog(LOG_INFO,
- "offset %.6f sec freq %.3f ppm error %.6f poll %d",
- last_offset, drift_comp * 1e6, sys_jitter,
- sys_poll);
-
record_sys_stats();
clock_stepcnt = 0;
ftemp = fabs(prev_drift_comp - drift_comp);
wander_resid = wander_threshold;
if ((fp = fopen(stats_temp_file, "w")) == NULL)
{
- msyslog(LOG_ERR, "can't open %s: %m",
+ msyslog(LOG_ERR,
+ "frequency file %s: %m",
stats_temp_file);
return;
}
stats_drift_file);
#else
/* we have no rename NFS of ftp in use */
- if ((fp = fopen(stats_drift_file, "w")) == NULL)
- {
- msyslog(LOG_ERR, "can't open %s: %m",
+ if ((fp = fopen(stats_drift_file, "w")) ==
+ NULL) {
+ msyslog(LOG_ERR,
+ "frequency file %s: %m",
stats_drift_file);
return;
}
#endif /* SYS_WINNT */
switch(item) {
- case STATS_FREQ_FILE:
+
+ /*
+ * Open and read frequency file.
+ */
+ case STATS_FREQ_FILE:
if (stats_drift_file != 0) {
- (void) free(stats_drift_file);
- (void) free(stats_temp_file);
+ free(stats_drift_file);
+ free(stats_temp_file);
stats_drift_file = 0;
stats_temp_file = 0;
}
break;
}
if (fscanf(fp, "%lf", &old_drift) != 1) {
- msyslog(LOG_ERR, "frequency format error in %s",
+ msyslog(LOG_ERR,
+ "format error frequency file %s",
stats_drift_file);
old_drift = 1e9;
fclose(fp);
fclose(fp);
old_drift /= 1e6;
prev_drift_comp = old_drift;
- msyslog(LOG_INFO,
+ msyslog(LOG_NOTICE,
"frequency initialized %.3f PPM from %s",
old_drift * 1e6, stats_drift_file);
-
- leap_file("/etc/ntp.leap");
-
break;
-
- case STATS_STATSDIR:
+
+ /*
+ * Specify statistics directory.
+ */
+ case STATS_STATSDIR:
/*
* HMS: the following test is insufficient:
*/
if (strlen(value) >= sizeof(statsdir)) {
msyslog(LOG_ERR,
- "value for statsdir too long (>%d, sigh)",
+ "statsdir too long (>%d, sigh)",
(int)sizeof(statsdir) - 1);
} else {
l_fp now;
}
break;
- case STATS_PID_FILE:
+ /*
+ * Open pid file.
+ */
+ case STATS_PID_FILE:
if ((fp = fopen(value, "w")) == NULL) {
- msyslog(LOG_ERR, "Can't open %s: %m", value);
+ msyslog(LOG_ERR, "pid file %s: %m",
+ value);
break;
}
- fprintf(fp, "%d", (int) getpid());
+ fprintf(fp, "%d", (int)getpid());
fclose(fp);;
break;
- case STATS_LEAP_FILE:
- leapseconds_file_name = invalue;
+ /*
+ * Read leapseconds file.
+ */
+ case STATS_LEAP_FILE:
+ if ((fp = fopen(value, "r")) == NULL) {
+ msyslog(LOG_ERR, "leapseconds file %s: %m",
+ value);
+ break;
+ }
+
+ if (leap_file(fp) < 0)
+ msyslog(LOG_ERR,
+ "format error leapseconds file %s",
+ value);
+ else
+ msyslog(LOG_NOTICE,
+ "leap epoch %lu expire %lu TAI offset %d from %s",
+ leap_sec, leap_expire, leap_tai, value);
+ fclose(fp);
break;
- default:
+ default:
/* oh well */
break;
}
void
record_clock_stats(
struct sockaddr_storage *addr,
- const char *text
+ const char *text /* timecode string */
)
{
l_fp now;
record_raw_stats(
struct sockaddr_storage *srcadr,
struct sockaddr_storage *dstadr,
- l_fp *t1,
- l_fp *t2,
- l_fp *t3,
- l_fp *t4
+ l_fp *t1, /* originate timestamp */
+ l_fp *t2, /* receiver timestamp */
+ l_fp *t3, /* transmit timestamp */
+ l_fp *t4 /* destination timestamp */
)
{
l_fp now;
* packets recieved
* packets processed
* current version
- * previous versions
- * declined
+ * previous version
* access denied
* bad length or format
* bad authentication
+ * declined
* rate exceeded
*/
void
"%lu %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
day, ulfptoa(&now, 3), sys_stattime / 3600,
sys_received, sys_processed, sys_newversion,
- sys_oldversion, sys_declined,
- sys_restricted, sys_badlength, sys_badauth,
- sys_limitrejected);
+ sys_oldversion, sys_restricted, sys_badlength,
+ sys_badauth, sys_declined, sys_limitrejected);
fflush(sysstats.fp);
proto_clr_stats();
}
void
record_crypto_stats(
struct sockaddr_storage *addr,
- const char *text
+ const char *text /* text message */
)
{
l_fp now;
*/
void
record_timing_stats(
- const char *text
+ const char *text /* text message */
)
{
static unsigned int flshcnt;
* Read the ERTS leapsecond file in NIST text format and extract the
* NTP seconds of the latest leap and TAI offset after the leap.
*/
-static void
+static int
leap_file(
- char *cp /* file name */
+ FILE *fp /* file handle */
)
{
- FILE *str; /* file handle */
char buf[NTP_MAXSTRLEN]; /* file line buffer */
- u_long leapsec; /* NTP time at leap */
+ u_long leap; /* NTP time at leap */
u_long expire; /* NTP time when file expires */
int offset; /* TAI offset at leap (s) */
- char filename[MAXFILENAME]; /* name of leapseconds file */
-
- NTP_REQUIRE(cp != NULL);
-
- /*
- * Open the leapseconds file. If the first character of the
- * file name is not '/', prepend the keys directory string. If
- * the file is not found, ignore; if found with errors, report
- * to the log and ignore.
- */
- if (*cp == '/')
- strcpy(filename, cp);
- else
- snprintf(filename, MAXFILENAME, "%s/%s", keysdir, cp);
- if ((str = fopen(filename, "r")) == NULL)
- return;
+ int i;
/*
* Read and parse the leapseconds file. Empty lines and comments
* expiration time in NTP seconds. Other lines begin with two
* integers followed by junk or comments. The first integer is
* the NTP seconds at the leap, the second is the TAI offset
- * after the leap. Only the last correctly parsed line is
- * significant. Parsing errors are cheerfully ignored.
+ * after the leap.
*/
offset = 0;
- leapsec = 0;
+ leap = 0;
expire = 0;
- while (fgets(buf, NTP_MAXSTRLEN - 1, str) != NULL) {
+ i = 10;
+ while (fgets(buf, NTP_MAXSTRLEN - 1, fp) != NULL) {
if (strlen(buf) < 1)
continue;
if (strlen(buf) < 3)
continue;
- if (buf[1] == '@') {
- sscanf(&buf[2], "%lu", &expire);
+ /*
+ * Note the '@' flag was used only in the 2006
+ * table; previious to that the flag was '$'.
+ */
+ if (buf[1] == '@' || buf[1] == '$') {
+ if (sscanf(&buf[2], "%lu", &expire) !=
+ 1)
+ return (-1);
+
continue;
}
}
- sscanf(buf, "%lu %d", &leapsec, &offset);
+ if (sscanf(buf, "%lu %d", &leap, &offset) == 2) {
+
+ /*
+ * Valid offsets must increase by one for each
+ * leap.
+ */
+ if (i++ != offset)
+ return (-1);
+ }
}
- fclose(str);
+
+ /*
+ * There must be at least one leap.
+ */
+ if (i == 10)
+ return (-1);
+
leap_tai = offset;
- leap_sec = leapsec;
+ leap_sec = leap;
leap_expire = expire;
- msyslog(LOG_INFO,
- "leap_file: %s leap epoch %lu TAI offset %d expire %lu",
- cp, leap_sec, leap_tai, leap_expire);
+ return (0);
}
if (len == 0)
return;
- if (key_file_name != 0) {
- if (len > (int)strlen(key_file_name)) {
- (void) free(key_file_name);
- key_file_name = 0;
- }
+ if (key_file_name != NULL) {
+ free(key_file_name);
+ key_file_name = NULL;
}
-
- if (key_file_name == 0) {
+ if (key_file_name == NULL) {
#ifndef SYS_WINNT
- key_file_name = (char*)emalloc((u_int) (len + 1));
+ key_file_name = emalloc(len + 1);
#else
- key_file_name = (char*)emalloc((u_int) (MAXPATHLEN));
+ key_file_name = emalloc(MAXPATHLEN);
#endif
}
#ifndef SYS_WINNT
- memmove(key_file_name, keyfile, (unsigned)(len+1));
+ memmove(key_file_name, keyfile, len + 1);
#else
if (!ExpandEnvironmentStrings(keyfile, key_file_name,
MAXPATHLEN)) {
void
rereadkeys(void)
{
- if (key_file_name != 0)
- authreadkeys(key_file_name);
+ if (key_file_name != NULL)
+ authreadkeys(key_file_name);
}