xref: /netbsd-src/usr.sbin/timed/timedc/cmds.c (revision ce63d6c20fc4ec8ddc95c84bb229e3c4ecf82b69)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 static char sccsid[] = "@(#)cmds.c	2.8 (Berkeley) 3/2/91";
36 #endif /* not lint */
37 
38 #include "timedc.h"
39 #include <netinet/in_systm.h>
40 #include <netinet/ip.h>
41 #include <netinet/ip_icmp.h>
42 #define TSPTYPES
43 #include <protocols/timed.h>
44 #include <sys/file.h>
45 
46 int id;
47 int sock;
48 int sock_raw;
49 char hostname[MAXHOSTNAMELEN];
50 struct hostent *hp, *gethostbyname();
51 struct sockaddr_in server;
52 extern int measure_delta;
53 int bytenetorder(), bytehostorder();
54 char *strcpy();
55 
56 /*
57  * Clockdiff computes the difference between the time of the machine on
58  * which it is called and the time of the machines given as argument.
59  * The time differences measured by clockdiff are obtained using a sequence
60  * of ICMP TSTAMP messages which are returned to the sender by the IP module
61  * in the remote machine.
62  * In order to compare clocks of machines in different time zones, the time
63  * is transmitted (as a 32-bit value) in milliseconds since midnight UT.
64  * If a hosts uses a different time format, it should set the high order
65  * bit of the 32-bit quantity it transmits.
66  * However, VMS apparently transmits the time in milliseconds since midnight
67  * local time (rather than GMT) without setting the high order bit.
68  * Furthermore, it does not understand daylight-saving time.  This makes
69  * clockdiff behaving inconsistently with hosts running VMS.
70  *
71  * In order to reduce the sensitivity to the variance of message transmission
72  * time, clockdiff sends a sequence of messages.  Yet, measures between
73  * two `distant' hosts can be affected by a small error. The error can, however,
74  * be reduced by increasing the number of messages sent in each measurement.
75  */
76 
77 clockdiff(argc, argv)
78 int argc;
79 char *argv[];
80 {
81 	int measure_status;
82 	struct timeval ack;
83 	int measure();
84 
85 	if(argc < 2)  {
86 		printf("Usage: clockdiff host ... \n");
87 		return;
88 	}
89 
90 	id = getpid();
91 	(void)gethostname(hostname,sizeof(hostname));
92 
93 	while (argc > 1) {
94 		argc--; argv++;
95 		hp = gethostbyname(*argv);
96 		if (hp == NULL) {
97 			fprintf(stderr, "timed: %s: ", *argv);
98 			herror((char *)NULL);
99 			continue;
100 		}
101 		server.sin_family = hp->h_addrtype;
102 		bcopy(hp->h_addr, &(server.sin_addr.s_addr), hp->h_length);
103 		ack.tv_sec = 10;
104 		ack.tv_usec = 0;
105 		if ((measure_status = measure(&ack, &server)) < 0) {
106 			perror("measure");
107 			return;
108 		}
109 		switch (measure_status) {
110 
111 		case HOSTDOWN:
112 			printf("%s is down\n", hp->h_name);
113 			continue;
114 			break;
115 		case NONSTDTIME:
116 			printf("%s time transmitted in a non-standard format\n",						 hp->h_name);
117 			continue;
118 			break;
119 		case UNREACHABLE:
120 			printf("%s is unreachable\n", hp->h_name);
121 			continue;
122 			break;
123 		default:
124 			break;
125 		}
126 
127 		if (measure_delta > 0)
128 			printf("time on %s is %d ms. ahead of time on %s\n",
129 						hp->h_name, measure_delta,
130 						hostname);
131 		else
132 			if (measure_delta == 0)
133 		      		printf("%s and %s have the same time\n",
134 						hp->h_name, hostname);
135 			else
136 		      	     printf("time on %s is %d ms. behind time on %s\n",
137 					hp->h_name, -measure_delta, hostname);
138 	}
139 	return;
140 }
141 /*
142  * finds location of master timedaemon
143  */
144 
145 msite(argc)
146 int argc;
147 {
148 	int length;
149 	int cc;
150 	fd_set ready;
151 	struct sockaddr_in dest;
152 	struct timeval tout;
153 	struct sockaddr_in from;
154 	struct tsp msg;
155 	struct servent *srvp;
156 
157 	if (argc != 1) {
158 		printf("Usage: msite\n");
159 		return;
160 	}
161 
162 	srvp = getservbyname("timed", "udp");
163 	if (srvp == 0) {
164 		fprintf(stderr, "udp/timed: unknown service\n");
165 		return;
166 	}
167 	dest.sin_port = srvp->s_port;
168 	dest.sin_family = AF_INET;
169 
170 	(void)gethostname(hostname, sizeof(hostname));
171 	hp = gethostbyname(hostname);
172 	if (hp == NULL) {
173 		fprintf(stderr, "timed: %s: ", hostname);
174 		herror((char *)NULL);
175 		return;
176 	}
177 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
178 
179 	(void)strcpy(msg.tsp_name, hostname);
180 	msg.tsp_type = TSP_MSITE;
181 	msg.tsp_vers = TSPVERSION;
182 	bytenetorder(&msg);
183 	length = sizeof(struct sockaddr_in);
184 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
185 	    (struct sockaddr *)&dest, length) < 0) {
186 		perror("sendto");
187 		return;
188 	}
189 
190 	tout.tv_sec = 15;
191 	tout.tv_usec = 0;
192 	FD_ZERO(&ready);
193 	FD_SET(sock, &ready);
194 	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
195 		length = sizeof(struct sockaddr_in);
196 		cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0,
197 		    (struct sockaddr *)&from, &length);
198 		if (cc < 0) {
199 			perror("recvfrom");
200 			return;
201 		}
202 		bytehostorder(&msg);
203 		if (msg.tsp_type == TSP_ACK)
204 			printf("master timedaemon runs on %s\n", msg.tsp_name);
205 		else
206 			printf("received wrong ack: %s\n",
207 						tsptype[msg.tsp_type]);
208 	} else
209 		printf("communication error\n");
210 }
211 
212 /*
213  * quits timedc
214  */
215 
216 quit()
217 {
218 	exit(0);
219 }
220 
221 #define MAXH	4	/* max no. of hosts where election can occur */
222 
223 /*
224  * Causes the election timer to expire on the selected hosts
225  * It sends just one udp message per machine, relying on
226  * reliability of communication channel.
227  */
228 
229 testing(argc, argv)
230 int argc;
231 char *argv[];
232 {
233 	int length;
234 	int nhosts;
235 	struct servent *srvp;
236 	struct sockaddr_in sin[MAXH];
237 	struct tsp msg;
238 
239 	if(argc < 2)  {
240 		printf("Usage: testing host ...\n");
241 		return;
242 	}
243 
244 	srvp = getservbyname("timed", "udp");
245 	if (srvp == 0) {
246 		fprintf(stderr, "udp/timed: unknown service\n");
247 		return;
248 	}
249 
250 	nhosts = 0;
251 	while (argc > 1) {
252 		argc--; argv++;
253 		hp = gethostbyname(*argv);
254 		if (hp == NULL) {
255 			fprintf(stderr, "timed: %s: ", *argv);
256 			herror((char *)NULL);
257 			argc--; argv++;
258 			continue;
259 		}
260 		sin[nhosts].sin_port = srvp->s_port;
261 		sin[nhosts].sin_family = hp->h_addrtype;
262 		bcopy(hp->h_addr, &(sin[nhosts].sin_addr.s_addr), hp->h_length);
263 		if (++nhosts == MAXH)
264 			break;
265 	}
266 
267 	msg.tsp_type = TSP_TEST;
268 	msg.tsp_vers = TSPVERSION;
269 	(void)gethostname(hostname, sizeof(hostname));
270 	(void)strcpy(msg.tsp_name, hostname);
271 	bytenetorder(&msg);	/* it is not really necessary here */
272 	while (nhosts-- > 0) {
273 		length = sizeof(struct sockaddr_in);
274 		if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
275 		    (struct sockaddr *)&sin[nhosts], length) < 0) {
276 			perror("sendto");
277 			return;
278 		}
279 	}
280 }
281 
282 /*
283  * Enables or disables tracing on local timedaemon
284  */
285 
286 tracing(argc, argv)
287 int argc;
288 char *argv[];
289 {
290 	int onflag;
291 	int length;
292 	int cc;
293 	fd_set ready;
294 	struct sockaddr_in dest;
295 	struct timeval tout;
296 	struct sockaddr_in from;
297 	struct tsp msg;
298 	struct servent *srvp;
299 
300 	if (argc != 2) {
301 		printf("Usage: tracing { on | off }\n");
302 		return;
303 	}
304 
305 	srvp = getservbyname("timed", "udp");
306 	if (srvp == 0) {
307 		fprintf(stderr, "udp/timed: unknown service\n");
308 		return;
309 	}
310 	dest.sin_port = srvp->s_port;
311 	dest.sin_family = AF_INET;
312 
313 	(void)gethostname(hostname,sizeof(hostname));
314 	hp = gethostbyname(hostname);
315 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
316 
317 	if (strcmp(argv[1], "on") == 0) {
318 		msg.tsp_type = TSP_TRACEON;
319 		onflag = ON;
320 	} else {
321 		msg.tsp_type = TSP_TRACEOFF;
322 		onflag = OFF;
323 	}
324 
325 	(void)strcpy(msg.tsp_name, hostname);
326 	msg.tsp_vers = TSPVERSION;
327 	bytenetorder(&msg);
328 	length = sizeof(struct sockaddr_in);
329 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
330 	    (struct sockaddr *)&dest, length) < 0) {
331 		perror("sendto");
332 		return;
333 	}
334 
335 	tout.tv_sec = 5;
336 	tout.tv_usec = 0;
337 	FD_ZERO(&ready);
338 	FD_SET(sock, &ready);
339 	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
340 		length = sizeof(struct sockaddr_in);
341 		cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0,
342 		    (struct sockaddr *)&from, &length);
343 		if (cc < 0) {
344 			perror("recvfrom");
345 			return;
346 		}
347 		bytehostorder(&msg);
348 		if (msg.tsp_type == TSP_ACK)
349 			if (onflag)
350 				printf("timed tracing enabled\n");
351 			else
352 				printf("timed tracing disabled\n");
353 		else
354 			printf("wrong ack received: %s\n",
355 						tsptype[msg.tsp_type]);
356 	} else
357 		printf("communication error\n");
358 }
359 
360 priv_resources()
361 {
362 	int port;
363 	struct sockaddr_in sin;
364 
365 	sock = socket(AF_INET, SOCK_DGRAM, 0);
366 	if (sock < 0) {
367 		perror("opening socket");
368 		return(-1);
369 	}
370 
371 	sin.sin_family = AF_INET;
372 	sin.sin_addr.s_addr = 0;
373 	for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
374 		sin.sin_port = htons((u_short)port);
375 		if (bind(sock, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
376 			break;
377 		if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
378 			perror("bind");
379 			(void) close(sock);
380 			return(-1);
381 		}
382 	}
383 	if (port == IPPORT_RESERVED / 2) {
384 		fprintf(stderr, "all reserved ports in use\n");
385 		(void) close(sock);
386 		return(-1);
387 	}
388 
389 	sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
390 	if (sock_raw < 0)  {
391 		perror("opening raw socket");
392 		(void) close(sock_raw);
393 		return(-1);
394 	}
395 	return(1);
396 }
397