diff options
author | Jakob Schlyter <jakob@cvs.openbsd.org> | 2002-05-16 10:46:35 +0000 |
---|---|---|
committer | Jakob Schlyter <jakob@cvs.openbsd.org> | 2002-05-16 10:46:35 +0000 |
commit | 8293b72e756f1e92eb843751545baf14fee0e998 (patch) | |
tree | 748e7d3a9ed04e671cdefcb6bc57a500693fb4a3 /usr.sbin | |
parent | 7dedd3195a433530aa80264261f0b0bda40f3c7f (diff) |
add support for SNTP & split out RFC868 time support. ok deraadt@
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/rdate/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/rdate/ntp.c | 474 | ||||
-rw-r--r-- | usr.sbin/rdate/rdate.8 | 6 | ||||
-rw-r--r-- | usr.sbin/rdate/rdate.c | 108 | ||||
-rw-r--r-- | usr.sbin/rdate/rfc868time.c | 118 |
5 files changed, 637 insertions, 73 deletions
diff --git a/usr.sbin/rdate/Makefile b/usr.sbin/rdate/Makefile index d89e0d04951..b177d3d3c09 100644 --- a/usr.sbin/rdate/Makefile +++ b/usr.sbin/rdate/Makefile @@ -1,7 +1,7 @@ -# $OpenBSD: Makefile,v 1.4 1997/09/21 11:44:12 deraadt Exp $ +# $OpenBSD: Makefile,v 1.5 2002/05/16 10:46:34 jakob Exp $ PROG= rdate -SRCS= rdate.c +SRCS= rdate.c rfc868time.c ntp.c DPADD+= ${LIBUTIL} LDADD+= -lutil diff --git a/usr.sbin/rdate/ntp.c b/usr.sbin/rdate/ntp.c new file mode 100644 index 00000000000..ce456b7e9e4 --- /dev/null +++ b/usr.sbin/rdate/ntp.c @@ -0,0 +1,474 @@ +/* $OpenBSD: ntp.c,v 1.1 2002/05/16 10:46:34 jakob Exp $ */ + +/* + * Copyright (c) 1996, 1997 by N.M. Maclaren. All rights reserved. + * Copyright (c) 1996, 1997 by University of Cambridge. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the university may be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <float.h> +#include <limits.h> +#include <math.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + + +/* NTP definitions. Note that these assume 8-bit bytes - sigh. There + * is little point in parameterising everything, as it is neither + * feasible nor useful. It would be very useful if more fields could + * be defined as unspecified. The NTP packet-handling routines + * contain a lot of extra assumptions. */ + +#define JAN_1970 2208988800.0 /* 1970 - 1900 in seconds */ +#define NTP_SCALE 4294967296.0 /* 2^32, of course! */ + +#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_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_INSANITY 3600.0 /* Errors beyond this are hopeless */ + +#define NTP_PACKET_MIN 48 /* Without authentication */ +#define NTP_PACKET_MAX 68 /* With authentication (ignored) */ + +#define NTP_DISP_FIELD 8 /* Offset of dispersion field */ +#define NTP_REFERENCE 16 /* Offset of reference timestamp */ +#define NTP_ORIGINATE 24 /* Offset of originate timestamp */ +#define NTP_RECEIVE 32 /* Offset of receive timestamp */ +#define NTP_TRANSMIT 40 /* Offset of transmit timestamp */ + +#define MAX_QUERIES 25 +#define MAX_DELAY 15 + +#define MILLION_L 1000000l /* For conversion to/from timeval */ +#define MILLION_D 1.0e6 /* Must be equal to MILLION_L */ + + +struct ntp_data { + unsigned char status; + unsigned char version; + unsigned char mode; + unsigned char stratum; + unsigned char polling; + unsigned char precision; + double dispersion; + double reference; + double originate; + double receive; + double transmit; + double current; +}; + + +void ntp_client(const char *, struct timeval *, struct timeval *); +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(unsigned char *, int, struct ntp_data *); +void unpack_ntp(struct ntp_data *, unsigned char *, int); +double current_time(double); +void create_timeval(double, struct timeval *, struct timeval *); + +void +ntp_client(const char *hostname, struct timeval *new, struct timeval *adjust) +{ + struct hostent *hp; + struct servent *sp, ssp; + struct protoent *pp, ppp; + struct sockaddr_in server, peer; + + int s; + int packets = 0; + double offset, error; + + if ((hp = gethostbyname(hostname)) == NULL) + errx(1, "%s: %s", hostname, hstrerror(h_errno)); + + if ((sp = getservbyname("ntp", "udp")) == NULL) { + sp = &ssp; + sp->s_port = 123; + sp->s_proto = "udp"; + } + + if ((pp = getprotobyname(sp->s_proto)) == NULL) { + pp = &ppp; + pp->p_proto = 17; + } + + if ((s = socket(AF_INET, SOCK_DGRAM, pp->p_proto)) == -1) + err(1, "Could not create socket"); + + bzero(&peer, sizeof(peer)); + peer.sin_family = AF_INET; + peer.sin_port = sp->s_port; + (void) memcpy(&(peer.sin_addr.s_addr), hp->h_addr, hp->h_length); + + bzero(&server, sizeof(server)); + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + + if (bind(s, (struct sockaddr *) &server, sizeof(server))) + err(1, "Could not bind to socket"); + + packets = sync_ntp(s, (struct sockaddr *) &peer, &offset, &error); + + close(s); + + if (packets == 0) + errx(1, "No acceptable packets received"); + + if (error > NTP_INSANITY) + errx(1, "Unable to get a reasonable time estimate"); + + fprintf(stderr,"Correction: %.6f +/- %.6f\n", offset,error); + + create_timeval(offset, new, adjust); +} + +int +sync_ntp(int fd, const struct sockaddr *peer, double *offset, double *error) +{ + int attempts = 0, accepts = 0, rejects = 0; + int delay = MAX_DELAY; + + 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; + + while (accepts < MAX_QUERIES && attempts < 2 * MAX_QUERIES) { + if (current_time(JAN_1970) > deadline) + errx(1, "Not enough valid responses received in time"); + + make_packet(&data); + write_packet(fd, peer, &data); + + if (read_packet(fd, &data, &x, &y, &dispersion)) { + if (++rejects > MAX_QUERIES) + errx(1, "Too many bad or lost packets"); + else + continue; + } else + ++accepts; + + fprintf(stderr,"Offset: %.6f +/- %.6f disp=%.6f\n", + x, y, dispersion); + + if ((a = x - *offset) < 0.0) a = -a; + if (accepts <= 1) a = 0.0; + b = *error + y; + if (y < *error) { + *offset = x; + *error = y; + } + + fprintf(stderr,"Best: %.6f +/- %.6f\n", *offset, *error); + + if (a > b) + errx(1, "Inconsistent times recieved from NTP server"); + + if (*error <= minerr) break; + } + + return accepts; +} + +/* Create an outgoing NTP packet */ +void +make_packet(struct ntp_data *data) +{ + data->status = 0; + 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 = data->originate = 0.0; + data->current = data->transmit = current_time(JAN_1970); +} + +int +write_packet(int fd, const struct sockaddr *peer, struct ntp_data *data) +{ + unsigned char transmit[NTP_PACKET_MIN]; + int length; + + pack_ntp(transmit, NTP_PACKET_MIN, data); + length = sendto(fd, transmit, NTP_PACKET_MIN, 0, peer, sizeof(*peer)); + if(length <= 0) { + warnx("Unable to send NTP packet to server"); + return 1; + } + + return 0; +} + +/* Check the packet and work out the offset and optionally the error. + * Note that this contains more checking than xntp does. Return 0 for + * success, 1 for failure. Note that it must not change its arguments + * if it fails. */ +int +read_packet(int fd, struct ntp_data *data, double *off, double *error, + double *dispersion) +{ + unsigned char receive[NTP_PACKET_MAX+1]; + double delay1, delay2, x, y; + int length; + fd_set rfds; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 1000000 * MAX_DELAY / MAX_QUERIES; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + if (select (fd + 1, &rfds, NULL, NULL, &tv) < 1) + return 1; /* failure or timeout */ + + length = recvfrom(fd, receive, NTP_PACKET_MAX + 1, 0, NULL, 0); + if (length <= 0) { + warnx("Unable to receive NTP packet from server"); + return 1; + } + + if (length < NTP_PACKET_MIN || length > NTP_PACKET_MAX) { + warnx("Invalid NTP packet size, packet reject"); + return 1; + } + + unpack_ntp(data, receive, length); + + if (data->version < NTP_VERSION_MIN || + data->version > NTP_VERSION_MAX) { + warnx("Invalid NTP version, packet rejected"); + return 1; + } + + if (data->mode != NTP_MODE_SERVER) { + warnx("Invalid NTP server mode, 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. */ + + delay1 = data->transmit - data->receive; + delay2 = data->current - data->originate; + + if (data->reference == 0.0 || + data->transmit == 0.0 || + data->receive == 0.0 || + (data->reference != 0.0 && data->receive < data->reference) || + delay1 < 0.0 || + delay1 > NTP_INSANITY || + delay2 < 0.0 || + delay2 > NTP_INSANITY || + data->dispersion > NTP_INSANITY) { + warnx("Incomprehensible NTP 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; +} + +/* 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(unsigned char *packet, int length, struct ntp_data *data) +{ + int i, k; + double d; + + memset(packet,0, (size_t)length); + + packet[0] = (data->status<<6)|(data->version<<3)|data->mode; + packet[1] = data->stratum; + packet[2] = data->polling; + packet[3] = data->precision; + + d = data->originate/NTP_SCALE; + for (i = 0; i < 8; ++i) { + if ((k = (int)(d *= 256.0)) >= 256) k = 255; + packet[NTP_ORIGINATE+i] = k; + d -= k; + } + + 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; + } + + d = data->transmit/NTP_SCALE; + for (i = 0; i < 8; ++i) { + if ((k = (int)(d *= 256.0)) >= 256) k = 255; + packet[NTP_TRANSMIT+i] = k; + d -= k; + } +} + +/* Unpack the essential data from an NTP packet, bypassing struct + * layout and endian problems. Note that it ignores fields irrelevant + * to SNTP. */ +void +unpack_ntp(struct ntp_data *data, unsigned char *packet, int length) +{ + int i; + double d; + + data->current = current_time(JAN_1970); + + data->status = (packet[0] >> 6); + 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_ORIGINATE+i]; + data->originate = d/NTP_SCALE; + + for (i = 0, d = 0.0; i < 8; ++i) + d = 256.0*d+packet[NTP_RECEIVE+i]; + data->receive = d/NTP_SCALE; + + for (i = 0, d = 0.0; i < 8; ++i) + d = 256.0*d+packet[NTP_TRANSMIT+i]; + data->transmit = d/NTP_SCALE; +} + +/* Get the current UTC time in seconds since the Epoch plus an offset + * (usually the time from the beginning of the century to the Epoch) + * */ +double +current_time(double offset) +{ + struct timeval current; + + if (gettimeofday(¤t, NULL)) + err(1, "Could not get local time of day"); + + return offset + current.tv_sec + 1.0e-6 * current.tv_usec; +} + +/* Change offset into current UTC time. This is portable, even if + * struct timeval uses an unsigned long for tv_sec. */ +void +create_timeval(double difference, struct timeval *new, struct timeval *adjust) +{ + struct timeval old; + long n; + + /* Start by converting to timeval format. Note that we have to + * cater for negative, unsigned values. */ + if ((n = (long) difference) > difference) + --n; + adjust->tv_sec = n; + adjust->tv_usec = (long) (MILLION_D * (difference-n)); + errno = 0; + if (gettimeofday(&old, NULL)) + err(1, "Could not get local time of day"); + new->tv_sec = old.tv_sec + adjust->tv_sec; + new->tv_usec = (n = (long) old.tv_usec + (long) adjust->tv_usec); + + if (n < 0) { + new->tv_usec += MILLION_L; + --new->tv_sec; + } else if (n >= MILLION_L) { + new->tv_usec -= MILLION_L; + ++new->tv_sec; + } +} + +#ifdef DEBUG +void +print_packet(const struct ntp_data *data) +{ + printf("status: %u\n", data->status); + 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); +}; +#endif diff --git a/usr.sbin/rdate/rdate.8 b/usr.sbin/rdate/rdate.8 index 8ac7a5b91b2..435d04a2a0a 100644 --- a/usr.sbin/rdate/rdate.8 +++ b/usr.sbin/rdate/rdate.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: rdate.8,v 1.13 2001/08/03 16:03:02 mpech Exp $ +.\" $OpenBSD: rdate.8,v 1.14 2002/05/16 10:46:34 jakob Exp $ .\" $NetBSD: rdate.8,v 1.4 1996/04/08 20:55:17 jtc Exp $ .\" .\" Copyright (c) 1994 Christos Zoulas @@ -37,7 +37,7 @@ .Nd set the system's date from a remote host .Sh SYNOPSIS .Nm rdate -.Op Fl psa +.Op Fl npsa .Ar host .Sh DESCRIPTION .Nm @@ -49,6 +49,8 @@ protocol which is usually implemented as a built-in service of .Pp The options are as follows: .Bl -tag -width Ds +.It Fl n +Use SNTP (RFC1361) instead RFC868 time protocol .It Fl p Do not set, just print the remote time .It Fl s diff --git a/usr.sbin/rdate/rdate.c b/usr.sbin/rdate/rdate.c index 621565a3638..f75c7532aa2 100644 --- a/usr.sbin/rdate/rdate.c +++ b/usr.sbin/rdate/rdate.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rdate.c,v 1.13 2002/02/19 19:39:40 millert Exp $ */ +/* $OpenBSD: rdate.c,v 1.14 2002/05/16 10:46:34 jakob Exp $ */ /* $NetBSD: rdate.c,v 1.4 1996/03/16 12:37:45 pk Exp $ */ /* @@ -42,7 +42,7 @@ #if 0 from: static char rcsid[] = "$NetBSD: rdate.c,v 1.3 1996/02/22 06:59:18 thorpej Exp $"; #else -static char rcsid[] = "$OpenBSD: rdate.c,v 1.13 2002/02/19 19:39:40 millert Exp $"; +static const char rcsid[] = "$OpenBSD: rdate.c,v 1.14 2002/05/16 10:46:34 jakob Exp $"; #endif #endif /* lint */ @@ -53,45 +53,38 @@ static char rcsid[] = "$OpenBSD: rdate.c,v 1.13 2002/02/19 19:39:40 millert Exp #include <err.h> #include <string.h> #include <sys/time.h> -#include <sys/socket.h> -#include <netdb.h> -#include <netinet/in.h> #include <unistd.h> #include <util.h> #include <time.h> -/* seconds from midnight Jan 1900 - 1970 */ -#define DIFFERENCE 2208988800UL +void rfc868time_client (const char *, struct timeval *, struct timeval *); +void ntp_client (const char *, struct timeval *, struct timeval *); + extern char *__progname; -static void +void usage() { - (void) fprintf(stderr, "Usage: %s [-psa] host\n", __progname); + (void) fprintf(stderr, "Usage: %s [-npsa] host\n", __progname); + (void) fprintf(stderr, " -n: use SNTP instead of RFC868 time protocol\n"); (void) fprintf(stderr, " -p: just print, don't set\n"); (void) fprintf(stderr, " -s: just set, don't print\n"); (void) fprintf(stderr, " -a: use adjtime instead of instant change\n"); } int -main(argc, argv) - int argc; - char *argv[]; +main(int argc, char **argv) { - int pr = 0, silent = 0, s; + int pr = 0, silent = 0, ntp = 0; int slidetime = 0; - int adjustment; - time_t tim; char *hname; - struct hostent *hp; - struct protoent *pp, ppp; - struct servent *sp, ssp; - struct sockaddr_in sa; extern int optind; int c; - while ((c = getopt(argc, argv, "psa")) != -1) + struct timeval new, adjust; + + while ((c = getopt(argc, argv, "psan")) != -1) switch (c) { case 'p': pr++; @@ -105,6 +98,10 @@ main(argc, argv) slidetime++; break; + case 'n': + ntp++; + break; + default: usage(); return 1; @@ -116,58 +113,19 @@ main(argc, argv) } hname = argv[optind]; - if ((hp = gethostbyname(hname)) == NULL) { - warnx("%s: %s", hname, hstrerror(h_errno)); - return 1; - } - - if ((sp = getservbyname("time", "tcp")) == NULL) { - sp = &ssp; - sp->s_port = 37; - sp->s_proto = "tcp"; - } - if ((pp = getprotobyname(sp->s_proto)) == NULL) { - pp = &ppp; - pp->p_proto = 6; - } - if ((s = socket(AF_INET, SOCK_STREAM, pp->p_proto)) == -1) - err(1, "Could not create socket"); - - bzero(&sa, sizeof sa); - sa.sin_family = AF_INET; - sa.sin_port = sp->s_port; - - (void) memcpy(&(sa.sin_addr.s_addr), hp->h_addr, hp->h_length); - - if (connect(s, (struct sockaddr *) & sa, sizeof(sa)) == -1) - err(1, "Could not connect socket"); - - if (read(s, &tim, sizeof(time_t)) != sizeof(time_t)) - err(1, "Could not read data"); - - (void) close(s); - tim = ntohl(tim) - DIFFERENCE; - - if (slidetime) { - struct timeval tv_current; - if (gettimeofday(&tv_current, NULL) == -1) - err(1, "Could not get local time of day"); - adjustment = tim - tv_current.tv_sec; - } + if (ntp) + ntp_client(hname, &new, &adjust); + else + rfc868time_client(hname, &new, &adjust); if (!pr) { - struct timeval tv; if (!slidetime) { logwtmp("|", "date", ""); - tv.tv_sec = tim; - tv.tv_usec = 0; - if (settimeofday(&tv, NULL) == -1) + if (settimeofday(&new, NULL) == -1) err(1, "Could not set time of day"); logwtmp("{", "date", ""); } else { - tv.tv_sec = adjustment; - tv.tv_usec = 0; - if (adjtime(&tv, NULL) == -1) + if (adjtime(&adjust, NULL) == -1) err(1, "Could not adjust time of day"); } } @@ -175,15 +133,27 @@ main(argc, argv) if (!silent) { struct tm *ltm; char buf[80]; + time_t tim = new.tv_sec; + double adjsec; ltm = localtime(&tim); (void) strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y\n", ltm); (void) fputs(buf, stdout); - if (slidetime) - (void) fprintf(stdout, - "%s: adjust local clock by %d seconds\n", - __progname, adjustment); + + adjsec = adjust.tv_sec + adjust.tv_usec / 1.0e6; + + if (slidetime) { + if (ntp) + (void) fprintf(stdout, + "%s: adjust local clock by %.6f seconds\n", + __progname, adjsec); + else + (void) fprintf(stdout, + "%s: adjust local clock by %ld seconds\n", + __progname, adjust.tv_sec); + } } + return 0; } diff --git a/usr.sbin/rdate/rfc868time.c b/usr.sbin/rdate/rfc868time.c new file mode 100644 index 00000000000..4f138837990 --- /dev/null +++ b/usr.sbin/rdate/rfc868time.c @@ -0,0 +1,118 @@ +/* $OpenBSD: rfc868time.c,v 1.1 2002/05/16 10:46:34 jakob Exp $ */ +/* $NetBSD: rdate.c,v 1.4 1996/03/16 12:37:45 pk Exp $ */ + +/* + * Copyright (c) 1994 Christos Zoulas + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christos Zoulas. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * rdate.c: Set the date from the specified host + * + * Uses the rfc868 time protocol at socket 37. + * Time is returned as the number of seconds since + * midnight January 1st 1900. + */ +#ifndef lint +#if 0 +from: static char rcsid[] = "$NetBSD: rdate.c,v 1.3 1996/02/22 06:59:18 thorpej Exp $"; +#else +static const char rcsid[] = "$OpenBSD: rfc868time.c,v 1.1 2002/05/16 10:46:34 jakob Exp $"; +#endif +#endif /* lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <stdio.h> +#include <ctype.h> +#include <err.h> +#include <string.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> +#include <unistd.h> +#include <util.h> +#include <time.h> + +/* seconds from midnight Jan 1900 - 1970 */ +#define DIFFERENCE 2208988800UL + + +void +rfc868time_client (const char *hostname, + struct timeval *new, struct timeval *adjust) +{ + struct hostent *hp; + struct servent *sp, ssp; + struct protoent *pp, ppp; + struct sockaddr_in sin; + + int s; + struct timeval old; + time_t tim; + + if ((hp = gethostbyname(hostname)) == NULL) + errx(1, "%s: %s", hostname, hstrerror(h_errno)); + + if ((sp = getservbyname("time", "tcp")) == NULL) { + sp = &ssp; + sp->s_port = 37; + sp->s_proto = "tcp"; + } + if ((pp = getprotobyname(sp->s_proto)) == NULL) { + pp = &ppp; + pp->p_proto = 6; + } + if ((s = socket(AF_INET, SOCK_STREAM, pp->p_proto)) == -1) + err(1, "Could not create socket"); + + bzero(&sin, sizeof sin); + sin.sin_family = AF_INET; + sin.sin_port = sp->s_port; + + (void) memcpy(&(sin.sin_addr.s_addr), hp->h_addr, hp->h_length); + + if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) + err(1, "Could not connect socket"); + + if (read(s, &tim, sizeof(time_t)) != sizeof(time_t)) + err(1, "Could not read data"); + + (void) close(s); + tim = ntohl(tim) - DIFFERENCE; + + if (gettimeofday(&old, NULL) == -1) + err(1, "Could not get local time of day"); + + adjust->tv_sec = tim - old.tv_sec; + adjust->tv_usec = 0; + + new->tv_sec = tim; + new->tv_usec = 0; +} |