summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/rdate/ntp.c304
1 files changed, 135 insertions, 169 deletions
diff --git a/usr.sbin/rdate/ntp.c b/usr.sbin/rdate/ntp.c
index 9479f7c1548..193f864d69b 100644
--- a/usr.sbin/rdate/ntp.c
+++ b/usr.sbin/rdate/ntp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ntp.c,v 1.20 2004/06/05 19:18:56 alexander Exp $ */
+/* $OpenBSD: ntp.c,v 1.21 2004/06/09 07:15:56 alexander Exp $ */
/*
* Copyright (c) 1996, 1997 by N.M. Maclaren. All rights reserved.
@@ -64,11 +64,11 @@
#define NTP_MODE_CLIENT 3 /* NTP client mode */
#define NTP_MODE_SERVER 4 /* NTP server mode */
-#define NTP_VERSION 3 /* The current version */
+#define NTP_VERSION 4 /* The current version */
#define NTP_VERSION_MIN 1 /* The minum valid version */
#define NTP_VERSION_MAX 4 /* The maximum valid version */
#define NTP_STRATUM_MIN 1 /* The minum valid stratum */
-#define NTP_STRATUM_MAX 15 /* The maximum valid stratum */
+#define NTP_STRATUM_MAX 14 /* The maximum valid stratum */
#define NTP_INSANITY 3600.0 /* Errors beyond this are hopeless */
#define NTP_PACKET_MIN 48 /* Without authentication */
@@ -92,33 +92,32 @@
#define MILLION_D 1.0e6 /* Must be equal to MILLION_L */
struct ntp_data {
- u_char status;
- u_char version;
- u_char mode;
- u_char stratum;
- u_char polling;
- u_char precision;
- double dispersion;
- double reference;
- double originate;
- double receive;
- double transmit;
- double current;
-
- u_int64_t xmitck;
- u_int64_t recvck;
+ u_char status;
+ u_char version;
+ u_char mode;
+ u_char stratum;
+ double receive;
+ double transmit;
+ double current;
+ u_int64_t recvck;
+
+ /* Local State */
+ double originate;
+ u_int64_t xmitck;
};
void ntp_client(const char *, int, struct timeval *, struct timeval *, int);
int sync_ntp(int, const struct sockaddr *, double *, double *);
-void make_packet(struct ntp_data *);
-int write_packet(int, const struct sockaddr *, struct ntp_data *);
-int read_packet(int, struct ntp_data *, double *, double *, double *);
-void pack_ntp(u_char *, int, struct ntp_data *);
-void unpack_ntp(struct ntp_data *, u_char *, int);
+int write_packet(int, struct ntp_data *);
+int read_packet(int, struct ntp_data *, double *, double *);
+void unpack_ntp(struct ntp_data *, u_char *);
double current_time(double);
void create_timeval(double, struct timeval *, struct timeval *);
+#if DEBUG
+void print_packet(const struct ntp_data *);
+#endif
+
int corrleaps;
void
@@ -127,7 +126,7 @@ ntp_client(const char *hostname, int family, struct timeval *new,
{
struct addrinfo hints, *res0, *res;
double offset, error;
- int packets = 0, s, ierror;
+ int accept = 0, ret, s, ierror;
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
@@ -148,8 +147,8 @@ ntp_client(const char *hostname, int family, struct timeval *new,
if (s < 0)
continue;
- packets = sync_ntp(s, res->ai_addr, &offset, &error);
- if (packets == 0) {
+ ret = sync_ntp(s, res->ai_addr, &offset, &error);
+ if (ret < 0) {
#ifdef DEBUG
fprintf(stderr, "try the next address\n");
#endif
@@ -157,10 +156,8 @@ ntp_client(const char *hostname, int family, struct timeval *new,
s = -1;
continue;
}
- if (error > NTP_INSANITY) {
- /* should we try the next address instead? */
- errx(1, "Unable to get a reasonable time estimate");
- }
+
+ accept++;
break;
}
freeaddrinfo(res0);
@@ -169,6 +166,10 @@ ntp_client(const char *hostname, int family, struct timeval *new,
fprintf(stderr,"Correction: %.6f +/- %.6f\n", offset,error);
#endif
+ if (accept < 1) {
+ errx(1, "Unable to get a reasonable time estimate");
+ }
+
create_timeval(offset, new, adjust);
}
@@ -176,35 +177,52 @@ int
sync_ntp(int fd, const struct sockaddr *peer, double *offset, double *error)
{
int attempts = 0, accepts = 0, rejects = 0;
- int delay = MAX_DELAY;
+ int delay = MAX_DELAY, ret;
double deadline;
double a, b, x, y;
double minerr = 0.1; /* Maximum ignorable variation */
- double dispersion = 0.0; /* The source dispersion in seconds */
struct ntp_data data;
deadline = current_time(JAN_1970) + delay;
*offset = 0.0;
*error = NTP_INSANITY;
+ if (connect(fd, peer, SA_LEN(peer)) < 0) {
+ warn("Failed to connect to server");
+ return -1;
+ }
+
while (accepts < MAX_QUERIES && attempts < 2 * MAX_QUERIES) {
- if (current_time(JAN_1970) > deadline)
- errx(1, "Not enough valid responses received in time");
+ memset(&data, 0, sizeof(data));
- make_packet(&data);
- write_packet(fd, peer, &data);
+ if (current_time(JAN_1970) > deadline) {
+ warnx("Not enough valid responses received in time");
+ return -1;
+ }
- if (read_packet(fd, &data, &x, &y, &dispersion)) {
- if (++rejects > MAX_QUERIES)
- errx(1, "Too many bad or lost packets");
- else
- continue;
+ if (write_packet(fd, &data) < 0)
+ return -1;
+
+ ret = read_packet(fd, &data, &x, &y);
+
+ if (ret < 0)
+ return -1;
+ else if (ret > 0) {
+#ifdef DEBUG
+ print_packet(&data);
+#endif
+
+ if (++rejects > MAX_QUERIES) {
+ warnx("Too many bad or lost packets");
+ return -1;
+ } else
+ continue;
} else
++accepts;
#ifdef DEBUG
- fprintf(stderr,"Offset: %.6f +/- %.6f disp=%.6f\n",
- x, y, dispersion);
+ fprintf(stderr,"Offset: %.6f +/- %.6f\n",
+ x, y);
#endif
if ((a = x - *offset) < 0.0)
@@ -221,8 +239,10 @@ sync_ntp(int fd, const struct sockaddr *peer, double *offset, double *error)
fprintf(stderr,"Best: %.6f +/- %.6f\n", *offset, *error);
#endif
- if (a > b)
- errx(1, "Inconsistent times received from NTP server");
+ if (a > b) {
+ warnx("Inconsistent times received from NTP server");
+ return -1;
+ }
if (*error <= minerr)
break;
@@ -231,21 +251,18 @@ sync_ntp(int fd, const struct sockaddr *peer, double *offset, double *error)
return accepts;
}
-/* Create an outgoing NTP packet */
-void
-make_packet(struct ntp_data *data)
+/* Send out NTP packet. */
+int
+write_packet(int fd, struct ntp_data *data)
{
- data->status = STATUS_NOWARNING;
- data->version = NTP_VERSION;
- data->mode = NTP_MODE_CLIENT;
- data->stratum = 0;
- data->polling = 0;
- data->precision = 0;
- data->reference = data->dispersion = 0.0;
- data->receive = 0.0;
- data->current = data->transmit = current_time(JAN_1970);
- data->originate = data->transmit;
+ u_char packet[NTP_PACKET_MIN];
+ ssize_t length;
+
+ memset(packet, 0, sizeof(packet));
+
+ packet[0] = (NTP_VERSION << 3) | (NTP_MODE_CLIENT);
+ data->xmitck = (u_int64_t)arc4random() << 32 | arc4random();
/*
* Send out a random 64-bit number as our transmit time. The NTP
@@ -258,23 +275,20 @@ make_packet(struct ntp_data *data)
* getting spoofed by an attacker that can't capture our traffic
* but can spoof packets from the NTP server we're communicating with.
*
+ * No endian concerns here. Since we're running as a strict
+ * unicast client, we don't have to worry about anyone else finding
+ * the transmit field intelligible.
*/
- data->xmitck = ((u_int64_t)arc4random() << 32) | arc4random();
- data->recvck = 0;
-}
+ *(u_int64_t *)(packet + NTP_TRANSMIT) = data->xmitck;
-int
-write_packet(int fd, const struct sockaddr *peer, struct ntp_data *data)
-{
- u_char transmit[NTP_PACKET_MIN];
- ssize_t length;
+ data->originate = current_time(JAN_1970);
- pack_ntp(transmit, NTP_PACKET_MIN, data);
- length = sendto(fd, transmit, NTP_PACKET_MIN, 0, peer, SA_LEN(peer));
- if (length == -1) {
- warnx("Unable to send NTP packet to server");
- return 1;
+ length = write(fd, packet, sizeof(packet));
+
+ if (length != sizeof(packet)) {
+ warn("Unable to send NTP packet to server");
+ return -1;
}
return 0;
@@ -287,14 +301,13 @@ write_packet(int fd, const struct sockaddr *peer, struct ntp_data *data)
* if it fails.
*/
int
-read_packet(int fd, struct ntp_data *data, double *off, double *error,
- double *dispersion)
+read_packet(int fd, struct ntp_data *data, double *off, double *error)
{
- u_char receive[NTP_PACKET_MAX+1];
- double delay, x, y;
+ u_char receive[NTP_PACKET_MAX];
+ struct timeval tv;
+ double x, y;
int length, r;
fd_set *rfds;
- struct timeval tv;
rfds = (fd_set *)calloc(howmany(fd + 1, NFDBITS), sizeof(fd_mask));
if (!rfds) {
@@ -309,22 +322,31 @@ retry:
tv.tv_usec = 1000000 * MAX_DELAY / MAX_QUERIES;
r = select(fd + 1, rfds, NULL, NULL, &tv);
- if (r < 1 || !FD_ISSET(fd, rfds)) {
- if (r < 0) {
- if (errno == EINTR)
- goto retry;
- else
- warnx("select() failed");
- }
+
+ if (r < 0) {
+ if (errno == EINTR)
+ goto retry;
+ else
+ warn("select");
+
free(rfds);
+
+ return r;
+ }
+
+ if (r != 1 || !FD_ISSET(fd, rfds)) {
+ free(rfds);
+
return 1;
}
+
free(rfds);
- length = recvfrom(fd, receive, NTP_PACKET_MAX + 1, 0, NULL, 0);
+ length = read(fd, receive, NTP_PACKET_MAX);
+
if (length < 0) {
- warnx("Unable to receive NTP packet from server");
- return 1;
+ warn("Unable to receive NTP packet from server");
+ return -1;
}
if (length < NTP_PACKET_MIN || length > NTP_PACKET_MAX) {
@@ -332,16 +354,16 @@ retry:
return 1;
}
- unpack_ntp(data, receive, length);
+ unpack_ntp(data, receive);
if (data->recvck != data->xmitck) {
warnx("Invalid cookie received, packet rejected");
return 1;
}
- if (data->version < NTP_VERSION_MIN ||
- data->version > NTP_VERSION_MAX) {
- warnx("Invalid NTP version, packet rejected");
+ if (data->version != NTP_VERSION) {
+ warnx("Received different NTP version than sent,"
+ "packet rejected");
return 1;
}
@@ -350,76 +372,34 @@ retry:
return 1;
}
+ if (data->stratum < NTP_STRATUM_MIN ||
+ data->stratum > NTP_STRATUM_MAX) {
+ warnx("Invalid stratum received, packet rejected");
+ return 1;
+ }
+
if (data->status == STATUS_ALARM) {
warnx("Server clock not synchronized, packet rejected");
return 1;
}
- /*
- * Note that the conventions are very poorly defined in the NTP
- * protocol, so we have to guess. Any full NTP server perpetrating
- * completely unsynchronised packets is an abomination, anyway, so
- * reject it.
- */
- delay = data->transmit - data->receive;
-
- if (data->reference == 0.0 ||
- data->transmit == 0.0 ||
- data->receive == 0.0 ||
- (data->reference != 0.0 && data->receive < data->reference) ||
- delay < 0.0 ||
- delay > NTP_INSANITY ||
- data->dispersion > NTP_INSANITY) {
- warnx("Incomprehensible NTP packet rejected");
+ if (data->transmit == 0.0) {
+ warnx("Server clock invalid, packet rejected");
return 1;
}
- if (*dispersion < data->dispersion)
- *dispersion = data->dispersion;
-
x = data->receive - data->originate;
- y = (data->transmit == 0.0 ? 0.0 : data->transmit-data->current);
- *off = 0.5*(x+y);
- *error = x-y;
- x = data->current - data->originate;
- if (0.5*x > *error)
- *error = 0.5*x;
-
- return 0;
-}
+ y = data->transmit - data->current;
-/*
- * Pack the essential data into an NTP packet, bypassing struct layout
- * and endian problems. Note that it ignores fields irrelevant to
- * SNTP.
- */
-void
-pack_ntp(u_char *packet, int length, struct ntp_data *data)
-{
- int i, k;
- double d;
+ *off = (x + y) / 2;
+ *error = x - y;
- memset(packet,0, (size_t)length);
+ x = (data->current - data->originate) / 2;
- packet[0] = (data->status<<6)|(data->version<<3)|data->mode;
- packet[1] = data->stratum;
- packet[2] = data->polling;
- packet[3] = data->precision;
+ if (x > *error)
+ *error = x;
- d = data->receive/NTP_SCALE;
- for (i = 0; i < 8; ++i) {
- if ((k = (int)(d *= 256.0)) >= 256) k = 255;
- packet[NTP_RECEIVE+i] = k;
- d -= k;
- }
-
- /*
- * No endian concerns here. Since we're running as a strict
- * unicast client, we don't have to worry about anyone else finding
- * this field intelligible.
- */
-
- *(u_int64_t *)(packet + NTP_TRANSMIT) = data->xmitck;
+ return 0;
}
/*
@@ -428,7 +408,7 @@ pack_ntp(u_char *packet, int length, struct ntp_data *data)
* to SNTP.
*/
void
-unpack_ntp(struct ntp_data *data, u_char *packet, int length)
+unpack_ntp(struct ntp_data *data, u_char *packet)
{
int i;
double d;
@@ -436,19 +416,9 @@ unpack_ntp(struct ntp_data *data, u_char *packet, int length)
data->current = current_time(JAN_1970);
data->status = (packet[0] >> 6);
- data->version = (packet[0] >> 3)&0x07;
- data->mode = packet[0]&0x07;
+ data->version = (packet[0] >> 3) & 0x07;
+ data->mode = packet[0] & 0x07;
data->stratum = packet[1];
- data->polling = packet[2];
- data->precision = packet[3];
-
- for (i = 0, d = 0.0; i < 4; ++i)
- d = 256.0*d+packet[NTP_DISP_FIELD+i];
- data->dispersion = d/65536.0;
-
- for (i = 0, d = 0.0; i < 8; ++i)
- d = 256.0*d+packet[NTP_REFERENCE+i];
- data->reference = d/NTP_SCALE;
for (i = 0, d = 0.0; i < 8; ++i)
d = 256.0*d+packet[NTP_RECEIVE+i];
@@ -458,7 +428,7 @@ unpack_ntp(struct ntp_data *data, u_char *packet, int length)
d = 256.0*d+packet[NTP_TRANSMIT+i];
data->transmit = d/NTP_SCALE;
- /* See unpack_ntp for why there is no byte-order change. */
+ /* See write_packet for why this isn't an endian problem. */
data->recvck = *(u_int64_t *)(packet + NTP_ORIGINATE);
}
@@ -526,14 +496,10 @@ print_packet(const struct ntp_data *data)
printf("version: %u\n", data->version);
printf("mode: %u\n", data->mode);
printf("stratum: %u\n", data->stratum);
- printf("polling: %u\n", data->polling);
- printf("precision: %u\n", data->precision);
- printf("dispersion: %e\n", data->dispersion);
- printf("reference: %e\n", data->reference);
- printf("originate: %e\n", data->originate);
- printf("receive: %e\n", data->receive);
- printf("transmit: %e\n", data->transmit);
- printf("current: %e\n", data->current);
+ printf("originate: %f\n", data->originate);
+ printf("receive: %f\n", data->receive);
+ printf("transmit: %f\n", data->transmit);
+ printf("current: %f\n", data->current);
printf("xmitck: 0x%0llX\n", data->xmitck);
printf("recvck: 0x%0llX\n", data->recvck);
};