1 /* $OpenBSD: src/usr.sbin/rdate/ntp.c,v 1.27 2004/10/26 09:48:59 henning Exp $ */
2 /* $DragonFly: src/usr.sbin/rdate/ntp.c,v 1.1 2004/12/01 16:04:43 joerg Exp $ */
5 * Copyright (c) 1996, 1997 by N.M. Maclaren. All rights reserved.
6 * Copyright (c) 1996, 1997 by University of Cambridge. All rights reserved.
7 * Copyright (c) 2002 by Thorsten "mirabile" Glaser.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the author nor the university may be used to
18 * endorse or promote products derived from this software without
19 * specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/param.h>
34 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
57 * NTP definitions. Note that these assume 8-bit bytes - sigh. There
58 * is little point in parameterising everything, as it is neither
59 * feasible nor useful. It would be very useful if more fields could
60 * be defined as unspecified. The NTP packet-handling routines
61 * contain a lot of extra assumptions.
64 #define JAN_1970 2208988800.0 /* 1970 - 1900 in seconds */
65 #define NTP_SCALE 4294967296.0 /* 2^32, of course! */
67 #define NTP_MODE_CLIENT 3 /* NTP client mode */
68 #define NTP_MODE_SERVER 4 /* NTP server mode */
69 #define NTP_VERSION 4 /* The current version */
70 #define NTP_VERSION_MIN 1 /* The minum valid version */
71 #define NTP_VERSION_MAX 4 /* The maximum valid version */
72 #define NTP_STRATUM_MAX 14 /* The maximum valid stratum */
73 #define NTP_INSANITY 3600.0 /* Errors beyond this are hopeless */
75 #define NTP_PACKET_MIN 48 /* Without authentication */
76 #define NTP_PACKET_MAX 68 /* With authentication (ignored) */
78 #define NTP_DISP_FIELD 8 /* Offset of dispersion field */
79 #define NTP_REFERENCE 16 /* Offset of reference timestamp */
80 #define NTP_ORIGINATE 24 /* Offset of originate timestamp */
81 #define NTP_RECEIVE 32 /* Offset of receive timestamp */
82 #define NTP_TRANSMIT 40 /* Offset of transmit timestamp */
84 #define STATUS_NOWARNING 0 /* No Leap Indicator */
85 #define STATUS_LEAPHIGH 1 /* Last Minute Has 61 Seconds */
86 #define STATUS_LEAPLOW 2 /* Last Minute Has 59 Seconds */
87 #define STATUS_ALARM 3 /* Server Clock Not Synchronized */
89 #define MAX_QUERIES 25
92 #define MILLION_L 1000000l /* For conversion to/from timeval */
93 #define MILLION_D 1.0e6 /* Must be equal to MILLION_L */
110 static int sync_ntp(int, const struct sockaddr
*, double *, double *);
111 static int write_packet(int, struct ntp_data
*);
112 static int read_packet(int, struct ntp_data
*, double *, double *);
113 static void unpack_ntp(struct ntp_data
*, u_char
*);
114 static double current_time(double);
115 static void create_timeval(double, struct timeval
*, struct timeval
*);
118 void print_packet(const struct ntp_data
*);
121 static int corrleaps
;
124 ntp_client(const char *hostname
, int family
, struct timeval
*new,
125 struct timeval
*adjust
, int leapflag
)
127 struct addrinfo hints
, *res0
, *res
;
128 double offset
, error
;
129 int accepted
= 0, ret
, s
, ierror
;
131 memset(&hints
, 0, sizeof(hints
));
132 hints
.ai_family
= family
;
133 hints
.ai_socktype
= SOCK_DGRAM
;
134 ierror
= getaddrinfo(hostname
, "ntp", &hints
, &res0
);
136 errx(1, "%s: %s", hostname
, gai_strerror(ierror
));
138 corrleaps
= leapflag
;
143 for (res
= res0
; res
; res
= res
->ai_next
) {
144 s
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
148 ret
= sync_ntp(s
, res
->ai_addr
, &offset
, &error
);
151 fprintf(stderr
, "try the next address\n");
164 fprintf(stderr
, "Correction: %.6f +/- %.6f\n", offset
, error
);
168 errx(1, "Unable to get a reasonable time estimate");
170 create_timeval(offset
, new, adjust
);
174 sync_ntp(int fd
, const struct sockaddr
*peer
, double *offset
, double *error
)
176 int attempts
= 0, accepts
= 0, rejects
= 0;
177 int delay
= MAX_DELAY
, ret
;
180 double minerr
= 0.1; /* Maximum ignorable variation */
181 struct ntp_data data
;
183 deadline
= current_time(JAN_1970
) + delay
;
185 *error
= NTP_INSANITY
;
187 if (connect(fd
, peer
, peer
->sa_len
) < 0) {
188 warn("Failed to connect to server");
192 while (accepts
< MAX_QUERIES
&& attempts
< 2 * MAX_QUERIES
) {
193 memset(&data
, 0, sizeof(data
));
195 if (current_time(JAN_1970
) > deadline
) {
196 warnx("Not enough valid responses received in time");
200 if (write_packet(fd
, &data
) < 0)
203 ret
= read_packet(fd
, &data
, &x
, &y
);
212 if (++rejects
> MAX_QUERIES
) {
213 warnx("Too many bad or lost packets");
221 fprintf(stderr
, "Offset: %.6f +/- %.6f\n", x
, y
);
224 if ((a
= x
- *offset
) < 0.0)
235 fprintf(stderr
, "Best: %.6f +/- %.6f\n", *offset
, *error
);
239 warnx("Inconsistent times received from NTP server");
243 if (*error
<= minerr
)
250 /* Send out NTP packet. */
252 write_packet(int fd
, struct ntp_data
*data
)
254 uint8_t packet
[NTP_PACKET_MIN
];
257 memset(packet
, 0, sizeof(packet
));
259 packet
[0] = (NTP_VERSION
<< 3) | (NTP_MODE_CLIENT
);
261 data
->xmitck
= (uint64_t)arc4random() << 32 | arc4random();
264 * Send out a random 64-bit number as our transmit time. The NTP
265 * server will copy said number into the originate field on the
266 * response that it sends us. This is totally legal per the SNTP spec.
268 * The impact of this is two fold: we no longer send out the current
269 * system time for the world to see (which may aid an attacker), and
270 * it gives us a (not very secure) way of knowing that we're not
271 * getting spoofed by an attacker that can't capture our traffic
272 * but can spoof packets from the NTP server we're communicating with.
274 * No endian concerns here. Since we're running as a strict
275 * unicast client, we don't have to worry about anyone else finding
276 * the transmit field intelligible.
279 *(uint64_t *)(packet
+ NTP_TRANSMIT
) = data
->xmitck
;
281 data
->originate
= current_time(JAN_1970
);
283 length
= write(fd
, packet
, sizeof(packet
));
285 if (length
!= sizeof(packet
)) {
286 warn("Unable to send NTP packet to server");
294 * Check the packet and work out the offset and optionally the error.
295 * Note that this contains more checking than xntp does. Return 0 for
296 * success, 1 for failure. Note that it must not change its arguments
300 read_packet(int fd
, struct ntp_data
*data
, double *off
, double *error
)
302 uint8_t receive
[NTP_PACKET_MAX
];
308 rfds
= calloc(howmany(fd
+ 1, NFDBITS
), sizeof(fd_mask
));
316 tv
.tv_usec
= 1000000 * MAX_DELAY
/ MAX_QUERIES
;
318 r
= select(fd
+ 1, rfds
, NULL
, NULL
, &tv
);
330 if (r
!= 1 || !FD_ISSET(fd
, rfds
)) {
337 length
= read(fd
, receive
, NTP_PACKET_MAX
);
340 warn("Unable to receive NTP packet from server");
344 if (length
< NTP_PACKET_MIN
|| length
> NTP_PACKET_MAX
) {
345 warnx("Invalid NTP packet size, packet rejected");
349 unpack_ntp(data
, receive
);
351 if (data
->recvck
!= data
->xmitck
) {
352 warnx("Invalid cookie received, packet rejected");
356 if (data
->version
< NTP_VERSION_MIN
||
357 data
->version
> NTP_VERSION_MAX
) {
358 warnx("Received NTP version %u, need %u or lower",
359 data
->version
, NTP_VERSION
);
363 if (data
->mode
!= NTP_MODE_SERVER
) {
364 warnx("Invalid NTP server mode, packet rejected");
368 if (data
->stratum
> NTP_STRATUM_MAX
) {
369 warnx("Invalid stratum received, packet rejected");
373 if (data
->transmit
== 0.0) {
374 warnx("Server clock invalid, packet rejected");
378 x
= data
->receive
- data
->originate
;
379 y
= data
->transmit
- data
->current
;
384 x
= (data
->current
- data
->originate
) / 2;
393 * Unpack the essential data from an NTP packet, bypassing struct
394 * layout and endian problems. Note that it ignores fields irrelevant
398 unpack_ntp(struct ntp_data
*data
, u_char
*packet
)
403 data
->current
= current_time(JAN_1970
);
405 data
->status
= (packet
[0] >> 6);
406 data
->version
= (packet
[0] >> 3) & 0x07;
407 data
->mode
= packet
[0] & 0x07;
408 data
->stratum
= packet
[1];
410 for (i
= 0, d
= 0.0; i
< 8; ++i
)
411 d
= 256.0 * d
+ packet
[NTP_RECEIVE
+i
];
413 data
->receive
= d
/ NTP_SCALE
;
415 for (i
= 0, d
= 0.0; i
< 8; ++i
)
416 d
= 256.0 * d
+ packet
[NTP_TRANSMIT
+i
];
418 data
->transmit
= d
/ NTP_SCALE
;
420 /* See write_packet for why this isn't an endian problem. */
421 data
->recvck
= *(uint64_t *)(packet
+ NTP_ORIGINATE
);
425 * Get the current UTC time in seconds since the Epoch plus an offset
426 * (usually the time from the beginning of the century to the Epoch)
429 current_time(double offset
)
431 struct timeval current
;
434 if (gettimeofday(¤t
, NULL
))
435 err(1, "Could not get local time of day");
438 * At this point, current has the current TAI time.
439 * Now subtract leap seconds to set the posix tick.
442 t
= SEC_TO_TAI64(current
.tv_sec
);
446 return (offset
+ TAI64_TO_SEC(t
) + 1.0e-6 * current
.tv_usec
);
450 * Change offset into current UTC time. This is portable, even if
451 * struct timeval uses an unsigned long for tv_sec.
454 create_timeval(double difference
, struct timeval
*new, struct timeval
*adjust
)
459 /* Start by converting to timeval format. Note that we have to
460 * cater for negative, unsigned values. */
461 if ((n
= (long) difference
) > difference
)
464 adjust
->tv_usec
= (long) (MILLION_D
* (difference
-n
));
466 if (gettimeofday(&old
, NULL
))
467 err(1, "Could not get local time of day");
468 new->tv_sec
= old
.tv_sec
+ adjust
->tv_sec
;
469 new->tv_usec
= (n
= (long) old
.tv_usec
+ (long) adjust
->tv_usec
);
472 new->tv_usec
+= MILLION_L
;
474 } else if (n
>= MILLION_L
) {
475 new->tv_usec
-= MILLION_L
;
482 print_packet(const struct ntp_data
*data
)
484 printf("status: %u\n", data
->status
);
485 printf("version: %u\n", data
->version
);
486 printf("mode: %u\n", data
->mode
);
487 printf("stratum: %u\n", data
->stratum
);
488 printf("originate: %f\n", data
->originate
);
489 printf("receive: %f\n", data
->receive
);
490 printf("transmit: %f\n", data
->transmit
);
491 printf("current: %f\n", data
->current
);
492 printf("xmitck: 0x%0llX\n", data
->xmitck
);
493 printf("recvck: 0x%0llX\n", data
->recvck
);