From: Harlan Stenn Date: Sat, 26 Jan 2008 09:02:52 +0000 (-0500) Subject: much cleanup, fixes, and changes from Dave Mills X-Git-Tag: NTP_4_2_5P110~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9dd9cd09471f5658d23ba384ee278af20912bf45;p=thirdparty%2Fntp.git much cleanup, fixes, and changes from Dave Mills bk: 479af73cOUX0Xaf0PinjN5P8Ic6txA --- diff --git a/ChangeLog b/ChangeLog index 9170510a6..5d2f2eb9e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ +* 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. diff --git a/ntpd/ntp_crypto.c b/ntpd/ntp_crypto.c index 021e59033..ac5f89144 100644 --- a/ntpd/ntp_crypto.c +++ b/ntpd/ntp_crypto.c @@ -126,7 +126,7 @@ struct cert_info *cert_host = NULL; /* host certificate */ 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 */ @@ -645,8 +645,7 @@ crypto_recv( */ 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); @@ -1030,7 +1029,7 @@ crypto_recv( 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 @@ -1049,7 +1048,7 @@ crypto_recv( /* * 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); @@ -1069,7 +1068,7 @@ crypto_recv( /* * 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, @@ -1091,10 +1090,9 @@ crypto_recv( 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; @@ -1280,9 +1278,7 @@ crypto_xmit( */ 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; @@ -1292,15 +1288,14 @@ crypto_xmit( } /* - * 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) @@ -1477,8 +1472,8 @@ crypto_xmit( 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: @@ -1692,8 +1687,7 @@ crypto_encrypt( */ 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)); @@ -1780,7 +1774,7 @@ crypto_ident( 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); @@ -2000,7 +1994,7 @@ crypto_update(void) 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)); @@ -2118,35 +2112,38 @@ bighash( *********************************************************************** * * 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 @@ -2180,7 +2177,7 @@ crypto_alice( 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); } @@ -2247,7 +2244,7 @@ crypto_bob( * 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; @@ -2344,20 +2341,20 @@ crypto_iff( * 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); } @@ -2393,7 +2390,7 @@ crypto_iff( 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); } @@ -2407,20 +2404,25 @@ crypto_iff( *********************************************************************** * * 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 @@ -2477,7 +2479,7 @@ crypto_alice2( 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); } @@ -2544,7 +2546,7 @@ crypto_bob2( * 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; @@ -2644,20 +2646,20 @@ crypto_gq( * 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); } @@ -2679,7 +2681,7 @@ crypto_gq( * 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); @@ -2699,7 +2701,7 @@ crypto_gq( 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); } @@ -2711,8 +2713,7 @@ crypto_gq( * 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 @@ -2729,19 +2730,16 @@ crypto_gq( * 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 @@ -2752,31 +2750,34 @@ crypto_gq( * 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 * @@ -2804,7 +2805,7 @@ crypto_alice3( 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); } @@ -2870,7 +2871,7 @@ crypto_bob3( * 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; @@ -2887,8 +2888,8 @@ crypto_bob3( /* * 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(); @@ -2900,15 +2901,14 @@ crypto_bob3( 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 /* @@ -2973,25 +2973,25 @@ crypto_mv( * 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); @@ -3003,19 +3003,17 @@ crypto_mv( } /* - * 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; @@ -3023,7 +3021,7 @@ crypto_mv( 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); } @@ -3097,8 +3095,7 @@ cert_sign( 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); @@ -3114,9 +3111,10 @@ cert_sign( } /* - * 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)); @@ -3127,7 +3125,7 @@ cert_sign( 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); @@ -3162,7 +3160,7 @@ cert_sign( 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); @@ -3203,8 +3201,7 @@ cert_valid( 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); @@ -3382,18 +3379,15 @@ cert_parse( 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); @@ -3420,7 +3414,7 @@ cert_parse( 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); @@ -3443,7 +3437,7 @@ cert_parse( 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); @@ -3462,7 +3456,6 @@ cert_parse( 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) { @@ -3510,7 +3503,7 @@ cert_parse( * 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); @@ -3522,8 +3515,8 @@ cert_parse( /* * 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); @@ -3537,7 +3530,7 @@ cert_parse( * 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); @@ -3770,7 +3763,7 @@ crypto_cert( 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); @@ -3829,7 +3822,7 @@ crypto_setup(void) * the case of multiple crypto commands. */ if (crypto_flags & CRYPTO_FLAG_ENAB) { - msyslog(LOG_ERR, + msyslog(LOG_NOTICE, "crypto_setup: spurious crypto command"); return; } @@ -3917,8 +3910,6 @@ crypto_setup(void) 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. @@ -3954,21 +3945,11 @@ crypto_setup(void) 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. */ @@ -3978,30 +3959,28 @@ crypto_setup(void) 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_". + * "ntpkey_iffkey_". */ snprintf(filename, MAXFILENAME, "ntpkey_iffkey_%s", sys_groupname); @@ -4011,7 +3990,7 @@ crypto_setup(void) /* * Load optional GQ parameters from file - * "ntpkey_gq_". + * "ntpkey_gqkey_". */ snprintf(filename, MAXFILENAME, "ntpkey_gqkey_%s", sys_groupname); @@ -4021,7 +4000,7 @@ crypto_setup(void) /* * Load optional MV parameters from file - * "ntpkey_mv_". + * "ntpkey_mvkey_". */ snprintf(filename, MAXFILENAME, "ntpkey_mvkey_%s", sys_groupname); diff --git a/ntpd/ntp_intres.c b/ntpd/ntp_intres.c index 782df82b0..7fbe2c03d 100644 --- a/ntpd/ntp_intres.c +++ b/ntpd/ntp_intres.c @@ -1044,14 +1044,15 @@ readconf( 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); diff --git a/ntpd/ntp_loopfilter.c b/ntpd/ntp_loopfilter.c index 9090c9cc2..c70587703 100644 --- a/ntpd/ntp_loopfilter.c +++ b/ntpd/ntp_loopfilter.c @@ -47,6 +47,8 @@ #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 @@ -54,10 +56,10 @@ * 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 @@ -72,14 +74,14 @@ * 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 @@ -134,10 +136,14 @@ u_long clock_epoch; /* interval since last update */ 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 */ /* @@ -156,7 +162,7 @@ int mode_ntpdate = FALSE; /* exit on first clock set */ * 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 */ @@ -188,9 +194,10 @@ void 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); @@ -217,9 +224,7 @@ local_clock( { 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 */ /* @@ -255,16 +260,13 @@ local_clock( } /* - * 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) { @@ -314,16 +316,16 @@ local_clock( } /* - * 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) @@ -331,7 +333,7 @@ local_clock( 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) { @@ -354,8 +356,7 @@ local_clock( 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 */ @@ -384,14 +385,14 @@ local_clock( * 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); @@ -445,18 +446,19 @@ local_clock( /* * 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 @@ -467,7 +469,7 @@ local_clock( /* * 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 @@ -476,21 +478,22 @@ local_clock( */ 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; } @@ -547,17 +550,6 @@ local_clock( 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); @@ -578,17 +570,10 @@ local_clock( 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; } /* @@ -597,14 +582,13 @@ local_clock( * 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); } @@ -614,8 +598,7 @@ local_clock( #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. @@ -628,28 +611,27 @@ local_clock( 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); @@ -661,15 +643,16 @@ local_clock( 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 @@ -696,7 +679,7 @@ local_clock( } /* - * 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); @@ -707,11 +690,11 @@ local_clock( 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 */ @@ -758,8 +741,8 @@ adj_host_clock( */ 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; } @@ -767,8 +750,8 @@ adj_host_clock( * 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))); @@ -779,9 +762,7 @@ adj_host_clock( /* - * 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( @@ -790,8 +771,8 @@ 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 @@ -800,6 +781,57 @@ rstclock( 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 @@ -840,31 +872,23 @@ loop_config( #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 @@ -900,60 +924,58 @@ loop_config( 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); } @@ -961,18 +983,8 @@ loop_config( #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; @@ -1016,8 +1028,9 @@ loop_config( clock_minstep = freq; break; + case LOOP_LEAP: /* not used */ default: - msyslog(LOG_INFO, + msyslog(LOG_NOTICE, "loop_config: unsupported option %d", item); } } diff --git a/ntpd/ntp_monitor.c b/ntpd/ntp_monitor.c index 617b830e2..eca60304d 100644 --- a/ntpd/ntp_monitor.c +++ b/ntpd/ntp_monitor.c @@ -84,7 +84,7 @@ static int mon_mem_increments; /* times called malloc() */ * 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 */ /* @@ -268,14 +268,14 @@ ntp_monitor( 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; } diff --git a/ntpd/ntp_peer.c b/ntpd/ntp_peer.c index aedf4f1f3..900f3350d 100644 --- a/ntpd/ntp_peer.c +++ b/ntpd/ntp_peer.c @@ -921,14 +921,13 @@ expire_all(void) /* * 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; diff --git a/ntpd/ntp_proto.c b/ntpd/ntp_proto.c index e9bdbc69e..53762e2b4 100644 --- a/ntpd/ntp_proto.c +++ b/ntpd/ntp_proto.c @@ -92,9 +92,10 @@ u_long sys_epoch; /* last clock update time */ 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 */ @@ -124,7 +125,7 @@ u_long sys_newversion; /* current version */ 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 */ @@ -249,7 +250,8 @@ transmit( */ 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; @@ -260,7 +262,8 @@ transmit( * If timeout in Autokey dance, restart * the protocol. */ - if (peer->crypto) { + if (peer->crypto || (peer->flash & + TEST9)) { peer_clear(peer, "TIME"); peer->unreach = 0; } @@ -397,14 +400,6 @@ receive( 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 @@ -435,6 +430,18 @@ receive( } } + /* + * 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 @@ -448,12 +455,12 @@ receive( */ 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) { @@ -463,16 +470,28 @@ receive( } 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 @@ -481,7 +500,7 @@ receive( /* * 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 @@ -681,17 +700,22 @@ receive( /* * 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)) @@ -728,7 +752,6 @@ receive( */ if (AUTH(restrict_mask & RES_DONTTRUST, is_authentic)) fast_xmit(rbufp, hismode, skeyid, NULL); - return; /* hooray */ /* @@ -834,7 +857,7 @@ receive( * neither is Autokey. */ if (skeyid > NTP_MAXKEY) { - msyslog(LOG_INFO, + msyslog(LOG_NOTICE, "receive: autokey requires two-way communication"); sys_restricted++; return; /* no autokey */ @@ -1028,17 +1051,24 @@ receive( /* * 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; } } @@ -1113,12 +1143,13 @@ receive( 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 */ @@ -1169,7 +1200,7 @@ process_packet( 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, @@ -1184,6 +1215,22 @@ process_packet( 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 @@ -1212,33 +1259,14 @@ process_packet( } /* - * 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, @@ -1261,8 +1289,8 @@ process_packet( * 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: */ @@ -1326,6 +1354,14 @@ process_packet( .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; @@ -1377,8 +1413,8 @@ clock_update( { u_char ostratum; double dtemp; - l_fp now; u_long epoch; + l_fp now; #ifdef HAVE_LIBSCF_H char *fmri; #endif /* HAVE_LIBSCF_H */ @@ -1477,26 +1513,39 @@ clock_update( 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; /* @@ -1521,6 +1570,7 @@ poll_update( ) { int hpoll; + u_long next, utemp; /* * This routine figures out when the next poll should be sent. @@ -1552,59 +1602,81 @@ poll_update( 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); + 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 } @@ -1679,7 +1751,7 @@ peer_clear( /* * 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. */ @@ -1687,10 +1759,11 @@ peer_clear( 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); @@ -2199,8 +2272,7 @@ clock_select(void) nlist = 1; } else { if (osys_peer != NULL) { - NLOG(NLOG_SYNCSTATUS) - msyslog(LOG_INFO, + msyslog(LOG_NOTICE, "no servers reachable"); report_event(EVNT_PEERSTCHG, NULL); } @@ -2276,24 +2348,29 @@ clock_select(void) * 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) @@ -2353,8 +2430,8 @@ clock_select(void) 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 @@ -2416,8 +2493,8 @@ clock_select(void) #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); } @@ -2526,7 +2603,7 @@ peer_xmit( 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", @@ -2623,7 +2700,7 @@ peer_xmit( /* * 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 @@ -2682,8 +2759,8 @@ peer_xmit( 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 && @@ -2695,7 +2772,7 @@ peer_xmit( /* * 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 @@ -2805,7 +2882,7 @@ peer_xmit( 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; @@ -2824,7 +2901,7 @@ peer_xmit( 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 @@ -2913,7 +2990,7 @@ fast_xmit( 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; @@ -3168,8 +3245,7 @@ default_get_precision(void) /* * 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) @@ -3369,7 +3445,7 @@ proto_config( break; default: - msyslog(LOG_INFO, + msyslog(LOG_NOTICE, "proto_config: unsupported option %d", item); } } diff --git a/ntpd/ntp_timer.c b/ntpd/ntp_timer.c index 5cbeb3c94..a30014a9a 100644 --- a/ntpd/ntp_timer.c +++ b/ntpd/ntp_timer.c @@ -47,10 +47,11 @@ volatile int alarm_flag; /* * 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 */ @@ -265,7 +266,6 @@ timer(void) { register struct peer *peer, *next_peer; u_int n; - l_fp now; /* * The basic timerevent is one second. This is used to adjust @@ -309,8 +309,7 @@ timer(void) */ 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); @@ -342,37 +341,32 @@ timer(void) } /* - * 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; } } @@ -420,7 +414,7 @@ timer(void) } /* - * Finally, write stats once per hour. + * Finally, write hourly stats. */ if (stats_timer <= current_time) { stats_timer += HOUR; diff --git a/ntpd/ntp_util.c b/ntpd/ntp_util.c index f01ee68a1..55874281f 100644 --- a/ntpd/ntp_util.c +++ b/ntpd/ntp_util.c @@ -106,7 +106,7 @@ static double prev_drift_comp; /* last frequency update */ /* * Static prototypes */ -static void leap_file(char *); +static int leap_file(FILE *); /* * init_util - initialize the utilities @@ -114,9 +114,9 @@ static void leap_file(char *); 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); @@ -128,9 +128,6 @@ init_util(void) #ifdef DEBUG_TIMING filegen_register(&statsdir[0], "timingstats", &timingstats); #endif /* DEBUG_TIMING */ - -leap_file("/etc/ntp.leap"); /***** temp for debug *****/ - } @@ -213,13 +210,6 @@ write_stats(void) 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); @@ -249,7 +239,8 @@ write_stats(void) 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; } @@ -265,9 +256,10 @@ write_stats(void) 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; } @@ -345,10 +337,14 @@ stats_config( #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; } @@ -383,7 +379,8 @@ stats_config( 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); @@ -393,15 +390,15 @@ stats_config( 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: @@ -410,7 +407,7 @@ stats_config( */ 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; @@ -473,20 +470,41 @@ stats_config( } 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; } @@ -586,7 +604,7 @@ record_loop_stats( void record_clock_stats( struct sockaddr_storage *addr, - const char *text + const char *text /* timecode string */ ) { l_fp now; @@ -620,10 +638,10 @@ void 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; @@ -655,11 +673,11 @@ record_raw_stats( * packets recieved * packets processed * current version - * previous versions - * declined + * previous version * access denied * bad length or format * bad authentication + * declined * rate exceeded */ void @@ -680,9 +698,8 @@ record_sys_stats(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(); } @@ -702,7 +719,7 @@ record_sys_stats(void) void record_crypto_stats( struct sockaddr_storage *addr, - const char *text + const char *text /* text message */ ) { l_fp now; @@ -739,7 +756,7 @@ record_crypto_stats( */ void record_timing_stats( - const char *text + const char *text /* text message */ ) { static unsigned int flshcnt; @@ -769,32 +786,16 @@ record_timing_stats( * 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 @@ -802,13 +803,13 @@ leap_file( * 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; @@ -816,20 +817,39 @@ leap_file( 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); } @@ -899,22 +919,19 @@ getauthkeys( 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)) { @@ -932,8 +949,8 @@ getauthkeys( void rereadkeys(void) { - if (key_file_name != 0) - authreadkeys(key_file_name); + if (key_file_name != NULL) + authreadkeys(key_file_name); }