1 /* $OpenBSD: src/usr.sbin/ntpd/client.c,v 1.60 2005/04/19 11:08:41 henning Exp $ */
4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 2004 Alexander Guy <alexander.guy@andern.org>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/param.h>
29 int client_update(struct ntp_peer
*);
30 void set_deadline(struct ntp_peer
*, time_t);
33 set_next(struct ntp_peer
*p
, time_t t
)
35 p
->next
= time(NULL
) + t
;
40 set_deadline(struct ntp_peer
*p
, time_t t
)
42 p
->deadline
= time(NULL
) + t
;
47 client_peer_init(struct ntp_peer
*p
)
49 if ((p
->query
= calloc(1, sizeof(struct ntp_query
))) == NULL
)
50 fatal("client_peer_init calloc");
52 p
->query
->msg
.status
= MODE_CLIENT
| (NTP_VERSION
<< 3);
53 p
->state
= STATE_NONE
;
55 p
->trustlevel
= TRUSTLEVEL_PATHETIC
;
58 return (client_addr_init(p
));
62 client_addr_init(struct ntp_peer
*p
)
64 struct sockaddr_in
*sa_in
;
65 struct sockaddr_in6
*sa_in6
;
68 for (h
= p
->addr
; h
!= NULL
; h
= h
->next
) {
69 switch (h
->ss
.ss_family
) {
71 sa_in
= (struct sockaddr_in
*)&h
->ss
;
72 if (ntohs(sa_in
->sin_port
) == 0)
73 sa_in
->sin_port
= htons(123);
76 sa_in6
= (struct sockaddr_in6
*)&h
->ss
;
77 if (ntohs(sa_in6
->sin6_port
) == 0)
78 sa_in6
->sin6_port
= htons(123);
81 fatal("king bula sez: wrong AF in client_addr_init");
93 client_nextaddr(struct ntp_peer
*p
)
98 if (p
->addr_head
.a
== NULL
) {
99 priv_host_dns(p
->addr_head
.name
, p
->id
);
103 if ((p
->addr
= p
->addr
->next
) == NULL
)
104 p
->addr
= p
->addr_head
.a
;
107 p
->trustlevel
= TRUSTLEVEL_PATHETIC
;
113 client_query(struct ntp_peer
*p
)
115 int tos
= IPTOS_LOWDELAY
;
117 if (p
->addr
== NULL
&& client_nextaddr(p
) == -1) {
118 set_next(p
, error_interval());
122 if (p
->query
->fd
== -1) {
123 struct sockaddr
*sa
= (struct sockaddr
*)&p
->addr
->ss
;
125 if ((p
->query
->fd
= socket(p
->addr
->ss
.ss_family
, SOCK_DGRAM
,
127 fatal("client_query socket");
128 if (connect(p
->query
->fd
, sa
, SA_LEN(sa
)) == -1) {
129 if (errno
== ECONNREFUSED
|| errno
== ENETUNREACH
||
130 errno
== EHOSTUNREACH
) {
132 set_next(p
, error_interval());
135 fatal("client_query connect");
137 if (p
->addr
->ss
.ss_family
== AF_INET
&& setsockopt(p
->query
->fd
,
138 IPPROTO_IP
, IP_TOS
, &tos
, sizeof(tos
)) == -1)
139 log_warn("setsockopt IPTOS_LOWDELAY");
143 * Send out a random 64-bit number as our transmit time. The NTP
144 * server will copy said number into the originate field on the
145 * response that it sends us. This is totally legal per the SNTP spec.
147 * The impact of this is two fold: we no longer send out the current
148 * system time for the world to see (which may aid an attacker), and
149 * it gives us a (not very secure) way of knowing that we're not
150 * getting spoofed by an attacker that can't capture our traffic
151 * but can spoof packets from the NTP server we're communicating with.
153 * Save the real transmit timestamp locally.
156 p
->query
->msg
.xmttime
.int_partl
= arc4random();
157 p
->query
->msg
.xmttime
.fractionl
= arc4random();
158 p
->query
->xmttime
= gettime();
160 if (ntp_sendmsg(p
->query
->fd
, NULL
, &p
->query
->msg
,
161 NTP_MSGSIZE_NOAUTH
, 0) == -1) {
162 set_next(p
, INTERVAL_QUERY_PATHETIC
);
166 p
->state
= STATE_QUERY_SENT
;
167 set_deadline(p
, QUERYTIME_MAX
);
173 client_dispatch(struct ntp_peer
*p
, u_int8_t settime
)
175 char buf
[NTP_MSGSIZE
];
178 double T1
, T2
, T3
, T4
;
181 if ((size
= recvfrom(p
->query
->fd
, &buf
, sizeof(buf
), 0,
182 NULL
, NULL
)) == -1) {
183 if (errno
== EHOSTUNREACH
|| errno
== EHOSTDOWN
||
184 errno
== ENETUNREACH
|| errno
== ENETDOWN
||
185 errno
== ECONNREFUSED
) {
186 client_log_error(p
, "recvfrom", errno
);
187 set_next(p
, error_interval());
195 ntp_getmsg(buf
, size
, &msg
);
197 if (msg
.orgtime
.int_partl
!= p
->query
->msg
.xmttime
.int_partl
||
198 msg
.orgtime
.fractionl
!= p
->query
->msg
.xmttime
.fractionl
)
201 if ((msg
.status
& LI_ALARM
) == LI_ALARM
|| msg
.stratum
== 0 ||
202 msg
.stratum
> NTP_MAXSTRATUM
) {
203 interval
= error_interval();
204 set_next(p
, interval
);
205 log_info("reply from %s: not synced, next query %ds",
206 log_sockaddr((struct sockaddr
*)&p
->addr
->ss
), interval
);
211 * From RFC 2030 (with a correction to the delay math):
213 * Timestamp Name ID When Generated
214 * ------------------------------------------------------------
215 * Originate Timestamp T1 time request sent by client
216 * Receive Timestamp T2 time request received by server
217 * Transmit Timestamp T3 time reply sent by server
218 * Destination Timestamp T4 time reply received by client
220 * The roundtrip delay d and local clock offset t are defined as
222 * d = (T4 - T1) - (T3 - T2) t = ((T2 - T1) + (T3 - T4)) / 2.
225 T1
= p
->query
->xmttime
;
226 T2
= lfp_to_d(msg
.rectime
);
227 T3
= lfp_to_d(msg
.xmttime
);
229 p
->reply
[p
->shift
].offset
= ((T2
- T1
) + (T3
- T4
)) / 2;
230 p
->reply
[p
->shift
].delay
= (T4
- T1
) - (T3
- T2
);
231 if (p
->reply
[p
->shift
].delay
< 0) {
232 interval
= error_interval();
233 set_next(p
, interval
);
234 log_info("reply from %s: negative delay %f",
235 log_sockaddr((struct sockaddr
*)&p
->addr
->ss
),
236 p
->reply
[p
->shift
].delay
);
239 p
->reply
[p
->shift
].error
= (T2
- T1
) - (T3
- T4
);
240 p
->reply
[p
->shift
].rcvd
= time(NULL
);
241 p
->reply
[p
->shift
].good
= 1;
243 p
->reply
[p
->shift
].status
.leap
= (msg
.status
& LIMASK
) >> 6;
244 p
->reply
[p
->shift
].status
.precision
= msg
.precision
;
245 p
->reply
[p
->shift
].status
.rootdelay
= sfp_to_d(msg
.rootdelay
);
246 p
->reply
[p
->shift
].status
.rootdispersion
= sfp_to_d(msg
.dispersion
);
247 p
->reply
[p
->shift
].status
.refid
= ntohl(msg
.refid
);
248 p
->reply
[p
->shift
].status
.reftime
= lfp_to_d(msg
.reftime
);
249 p
->reply
[p
->shift
].status
.poll
= msg
.ppoll
;
250 p
->reply
[p
->shift
].status
.stratum
= msg
.stratum
;
252 if (p
->trustlevel
< TRUSTLEVEL_PATHETIC
)
253 interval
= scale_interval(INTERVAL_QUERY_PATHETIC
);
254 else if (p
->trustlevel
< TRUSTLEVEL_AGRESSIVE
)
255 interval
= scale_interval(INTERVAL_QUERY_AGRESSIVE
);
257 interval
= scale_interval(INTERVAL_QUERY_NORMAL
);
259 set_next(p
, interval
);
260 p
->state
= STATE_REPLY_RECEIVED
;
262 /* every received reply which we do not discard increases trust */
263 if (p
->trustlevel
< TRUSTLEVEL_MAX
) {
264 if (p
->trustlevel
< TRUSTLEVEL_BADPEER
&&
265 p
->trustlevel
+ 1 >= TRUSTLEVEL_BADPEER
)
266 log_info("peer %s now valid",
267 log_sockaddr((struct sockaddr
*)&p
->addr
->ss
));
271 log_debug("reply from %s: offset %f delay %f, "
272 "next query %ds", log_sockaddr((struct sockaddr
*)&p
->addr
->ss
),
273 p
->reply
[p
->shift
].offset
, p
->reply
[p
->shift
].delay
, interval
);
277 priv_settime(p
->reply
[p
->shift
].offset
);
279 if (++p
->shift
>= OFFSET_ARRAY_SIZE
)
286 client_update(struct ntp_peer
*p
)
288 int i
, best
= 0, good
= 0;
292 * find the offset which arrived with the lowest delay
293 * use that as the peer update
294 * invalidate it and all older ones
297 for (i
= 0; good
== 0 && i
< OFFSET_ARRAY_SIZE
; i
++)
298 if (p
->reply
[i
].good
) {
303 for (; i
< OFFSET_ARRAY_SIZE
; i
++)
304 if (p
->reply
[i
].good
) {
306 if (p
->reply
[i
].delay
< p
->reply
[best
].delay
)
313 memcpy(&p
->update
, &p
->reply
[best
], sizeof(p
->update
));
316 for (i
= 0; i
< OFFSET_ARRAY_SIZE
; i
++)
317 if (p
->reply
[i
].rcvd
<= p
->reply
[best
].rcvd
)
318 p
->reply
[i
].good
= 0;
324 client_log_error(struct ntp_peer
*peer
, const char *operation
, int error
)
328 address
= log_sockaddr((struct sockaddr
*)&peer
->addr
->ss
);
329 if (peer
->lasterror
== error
) {
330 log_debug("%s %s", operation
, address
);
333 peer
->lasterror
= error
;
334 log_warn("%s %s", operation
, address
);