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