xref: /netbsd-src/bin/date/netdate.c (revision 60c10f9b2eb00680bb65feb4d308d85ed6b3ae19)
1*60c10f9bSchristos /* $NetBSD: netdate.c,v 1.30 2011/01/29 02:16:52 christos Exp $ */
249f0ad86Scgd 
361f28255Scgd /*-
4667b5ea1Smycroft  * Copyright (c) 1990, 1993
5667b5ea1Smycroft  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
15b5b29542Sagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
32a71a8b87Sthorpej #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3449f0ad86Scgd #if 0
355fc5415eSjtc static char sccsid[] = "@(#)netdate.c	8.2 (Berkeley) 4/28/95";
3649f0ad86Scgd #else
37*60c10f9bSchristos __RCSID("$NetBSD: netdate.c,v 1.30 2011/01/29 02:16:52 christos Exp $");
3849f0ad86Scgd #endif
3961f28255Scgd #endif /* not lint */
4061f28255Scgd 
4161f28255Scgd #include <sys/param.h>
4261f28255Scgd #include <sys/time.h>
4361f28255Scgd #include <sys/socket.h>
44667b5ea1Smycroft 
4561f28255Scgd #include <netinet/in.h>
4661f28255Scgd #include <netdb.h>
4761f28255Scgd #define TSPTYPES
4861f28255Scgd #include <protocols/timed.h>
49667b5ea1Smycroft 
50667b5ea1Smycroft #include <err.h>
51667b5ea1Smycroft #include <errno.h>
52826e3166Smycroft #include <poll.h>
5361f28255Scgd #include <stdio.h>
5461f28255Scgd #include <string.h>
55667b5ea1Smycroft #include <unistd.h>
56667b5ea1Smycroft 
57667b5ea1Smycroft #include "extern.h"
5861f28255Scgd 
59cd788d02Scbiere #define	WAITACK		2000	/* milliseconds */
60cd788d02Scbiere #define	WAITDATEACK	5000	/* milliseconds */
6161f28255Scgd 
62cd788d02Scbiere static const char *
tsp_type_to_string(const struct tsp * msg)63cd788d02Scbiere tsp_type_to_string(const struct tsp *msg)
64cd788d02Scbiere {
65cd788d02Scbiere 	unsigned i;
66cd788d02Scbiere 
67cd788d02Scbiere 	i = msg->tsp_type;
68cd788d02Scbiere 	return i < TSPTYPENUMBER ? tsptype[i] : "unknown";
69cd788d02Scbiere }
70cd788d02Scbiere 
7161f28255Scgd /*
7261f28255Scgd  * Set the date in the machines controlled by timedaemons by communicating the
7361f28255Scgd  * new date to the local timedaemon.  If the timedaemon is in the master state,
7461f28255Scgd  * it performs the correction on all slaves.  If it is in the slave state, it
7561f28255Scgd  * notifies the master that a correction is needed.
76*60c10f9bSchristos  * Returns 0 on success.  Returns > 0 on failure.
7761f28255Scgd  */
78667b5ea1Smycroft int
netsettime(time_t tval)79a824cb6aSwiz netsettime(time_t tval)
8061f28255Scgd {
81cd788d02Scbiere 	struct sockaddr_in dest;
8261f28255Scgd 	struct tsp msg;
83a824cb6aSwiz 	char hostname[MAXHOSTNAMELEN];
84a824cb6aSwiz 	struct servent *sp;
85cd788d02Scbiere 	struct pollfd ready;
86cd788d02Scbiere 	int found, s, timed_ack, waittime;
8761f28255Scgd 
8861f28255Scgd 	if ((sp = getservbyname("timed", "udp")) == NULL) {
89667b5ea1Smycroft 		warnx("udp/timed: unknown service");
90*60c10f9bSchristos 		return 2;
9161f28255Scgd 	}
9261f28255Scgd 
93bad15fd3Scgd 	(void)memset(&dest, 0, sizeof(dest));
946e381b4cSchristos #ifdef BSD4_4
95cd788d02Scbiere 	dest.sin_len = sizeof(dest);
966e381b4cSchristos #endif
9761f28255Scgd 	dest.sin_family = AF_INET;
98c7ad9c47Smycroft 	dest.sin_port = sp->s_port;
99c7ad9c47Smycroft 	dest.sin_addr.s_addr = htonl(INADDR_ANY);
10061f28255Scgd 	s = socket(AF_INET, SOCK_DGRAM, 0);
101*60c10f9bSchristos 	if (s == -1) {
10284b3179aSginsbach 		if (errno != EAFNOSUPPORT)
103667b5ea1Smycroft 			warn("timed");
104*60c10f9bSchristos 		return 2;
10561f28255Scgd 	}
10661f28255Scgd 
107f9a6471eSmycroft #ifdef IP_PORTRANGE
108cd788d02Scbiere 	{
109cd788d02Scbiere 		static const int on = IP_PORTRANGE_LOW;
110cd788d02Scbiere 
111*60c10f9bSchristos 		if (setsockopt(s, IPPROTO_IP, IP_PORTRANGE, &on,
112*60c10f9bSchristos 		    sizeof(on)) == -1) {
113c3c0dec6Slukem 			warn("setsockopt");
114c3c0dec6Slukem 			goto bad;
115c3c0dec6Slukem 		}
11661f28255Scgd 	}
117cd788d02Scbiere #endif
118c3c0dec6Slukem 
11961f28255Scgd 	msg.tsp_type = TSP_SETDATE;
12061f28255Scgd 	msg.tsp_vers = TSPVERSION;
121*60c10f9bSchristos 	if (gethostname(hostname, sizeof(hostname)) == -1) {
122667b5ea1Smycroft 		warn("gethostname");
12361f28255Scgd 		goto bad;
12461f28255Scgd 	}
125*60c10f9bSchristos 	(void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name));
126*60c10f9bSchristos 	msg.tsp_seq = htons((in_port_t)0);
127*60c10f9bSchristos 	msg.tsp_time.tv_sec = htonl((in_addr_t)tval); /* XXX: y2038 */
128*60c10f9bSchristos 	msg.tsp_time.tv_usec = htonl((in_addr_t)0);
129*60c10f9bSchristos 	if (connect(s, (const void *)&dest, sizeof(dest)) == -1) {
130667b5ea1Smycroft 		warn("connect");
13161f28255Scgd 		goto bad;
13261f28255Scgd 	}
133*60c10f9bSchristos 	if (send(s, &msg, sizeof(msg), 0) == -1) {
13461f28255Scgd 		if (errno != ECONNREFUSED)
135667b5ea1Smycroft 			warn("send");
13661f28255Scgd 		goto bad;
13761f28255Scgd 	}
13861f28255Scgd 
13961f28255Scgd 	timed_ack = -1;
14061f28255Scgd 	waittime = WAITACK;
141cd788d02Scbiere 	ready.fd = s;
142cd788d02Scbiere 	ready.events = POLLIN;
14361f28255Scgd loop:
144cd788d02Scbiere 	found = poll(&ready, 1, waittime);
145cd788d02Scbiere 
146cd788d02Scbiere 	{
147*60c10f9bSchristos 		socklen_t len;
148cd788d02Scbiere 		int error;
14961f28255Scgd 
150*60c10f9bSchristos 		len = sizeof(error);
151*60c10f9bSchristos 		if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) == -1) {
152*60c10f9bSchristos 			warn("getsockopt");
153*60c10f9bSchristos 			goto bad;
154*60c10f9bSchristos 		}
155*60c10f9bSchristos 		if (error) {
156*60c10f9bSchristos 			if (error != ECONNREFUSED) {
157*60c10f9bSchristos 				errno = error;
158667b5ea1Smycroft 				warn("send (delayed error)");
159*60c10f9bSchristos 			}
16061f28255Scgd 			goto bad;
16161f28255Scgd 		}
162cd788d02Scbiere 	}
16361f28255Scgd 
164cd788d02Scbiere 	if (found > 0 && ready.revents & POLLIN) {
165cd788d02Scbiere 		ssize_t ret;
166cd788d02Scbiere 
167*60c10f9bSchristos 		if ((ret = recv(s, &msg, sizeof(msg), 0)) == -1) {
16861f28255Scgd 			if (errno != ECONNREFUSED)
169cd788d02Scbiere 				warn("recv");
170cd788d02Scbiere 			goto bad;
171cd788d02Scbiere 		} else if ((size_t)ret < sizeof(msg)) {
172cd788d02Scbiere 			warnx("recv: incomplete packet");
17361f28255Scgd 			goto bad;
17461f28255Scgd 		}
175cd788d02Scbiere 
17661f28255Scgd 		msg.tsp_seq = ntohs(msg.tsp_seq);
17761f28255Scgd 		msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);
17861f28255Scgd 		msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);
17961f28255Scgd 		switch (msg.tsp_type) {
18061f28255Scgd 		case TSP_ACK:
18161f28255Scgd 			timed_ack = TSP_ACK;
18261f28255Scgd 			waittime = WAITDATEACK;
18361f28255Scgd 			goto loop;
18461f28255Scgd 		case TSP_DATEACK:
18561f28255Scgd 			(void)close(s);
186*60c10f9bSchristos 			return 0;
18761f28255Scgd 		default:
188667b5ea1Smycroft 			warnx("wrong ack received from timed: %s",
189cd788d02Scbiere 			    tsp_type_to_string(&msg));
19061f28255Scgd 			timed_ack = -1;
19161f28255Scgd 			break;
19261f28255Scgd 		}
19361f28255Scgd 	}
19461f28255Scgd 	if (timed_ack == -1)
195667b5ea1Smycroft 		warnx("can't reach time daemon, time set locally");
19661f28255Scgd 
19761f28255Scgd bad:
19861f28255Scgd 	(void)close(s);
199*60c10f9bSchristos 	return 2;
20061f28255Scgd }
201