xref: /csrg-svn/usr.sbin/timed/timedc/cmds.c (revision 33123)
123785Sgusella /*
223785Sgusella  * Copyright (c) 1983 Regents of the University of California.
3*33123Sbostic  * All rights reserved.
4*33123Sbostic  *
5*33123Sbostic  * Redistribution and use in source and binary forms are permitted
6*33123Sbostic  * provided that this notice is preserved and that due credit is given
7*33123Sbostic  * to the University of California at Berkeley. The name of the University
8*33123Sbostic  * may not be used to endorse or promote products derived from this
9*33123Sbostic  * software without specific prior written permission. This software
10*33123Sbostic  * is provided ``as is'' without express or implied warranty.
1123785Sgusella  */
1223785Sgusella 
1323785Sgusella #ifndef lint
14*33123Sbostic static char sccsid[] = "@(#)cmds.c	2.4 (Berkeley) 12/23/87";
15*33123Sbostic #endif /* not lint */
1623785Sgusella 
1723785Sgusella #include "timedc.h"
1823785Sgusella #include <netinet/in_systm.h>
1923785Sgusella #include <netinet/ip.h>
2023785Sgusella #include <netinet/ip_icmp.h>
2123785Sgusella #define TSPTYPES
2223785Sgusella #include <protocols/timed.h>
2323785Sgusella #include <sys/file.h>
2423785Sgusella 
2523785Sgusella int id;
2623785Sgusella int sock;
2723785Sgusella int sock_raw;
2824904Sbloom char hostname[MAXHOSTNAMELEN];
2923785Sgusella struct hostent *hp, *gethostbyname();
3023785Sgusella struct sockaddr_in server;
3123785Sgusella extern int measure_delta;
3223785Sgusella int bytenetorder(), bytehostorder();
3323785Sgusella char *strcpy();
3423785Sgusella 
3523785Sgusella /*
3623785Sgusella  * Clockdiff computes the difference between the time of the machine on
3723785Sgusella  * which it is called and the time of the machines given as argument.
3823785Sgusella  * The time differences measured by clockdiff are obtained using a sequence
3923785Sgusella  * of ICMP TSTAMP messages which are returned to the sender by the IP module
4023785Sgusella  * in the remote machine.
4123785Sgusella  * In order to compare clocks of machines in different time zones, the time
4223785Sgusella  * is transmitted (as a 32-bit value) in milliseconds since midnight UT.
4323785Sgusella  * If a hosts uses a different time format, it should set the high order
4423785Sgusella  * bit of the 32-bit quantity it transmits.
4523785Sgusella  * However, VMS apparently transmits the time in milliseconds since midnight
4623785Sgusella  * local time (rather than GMT) without setting the high order bit.
4723785Sgusella  * Furthermore, it does not understand daylight-saving time.  This makes
4823785Sgusella  * clockdiff behaving inconsistently with hosts running VMS.
4923785Sgusella  *
5023785Sgusella  * In order to reduce the sensitivity to the variance of message transmission
5123785Sgusella  * time, clockdiff sends a sequence of messages.  Yet, measures between
5223785Sgusella  * two `distant' hosts can be affected by a small error. The error can, however,
5323785Sgusella  * be reduced by increasing the number of messages sent in each measurement.
5423785Sgusella  */
5523785Sgusella 
5623785Sgusella clockdiff(argc, argv)
5723785Sgusella int argc;
5823785Sgusella char *argv[];
5923785Sgusella {
6023785Sgusella 	int measure_status;
6123785Sgusella 	struct timeval ack;
6223785Sgusella 	int measure();
6323785Sgusella 
6423785Sgusella 	if(argc < 2)  {
6523785Sgusella 		printf("Usage: clockdiff host ... \n");
6623785Sgusella 		return;
6723785Sgusella 	}
6823785Sgusella 
6923785Sgusella 	id = getpid();
7023785Sgusella 	(void)gethostname(hostname,sizeof(hostname));
7123785Sgusella 
7223785Sgusella 	while (argc > 1) {
7323785Sgusella 		argc--; argv++;
7423785Sgusella 		hp = gethostbyname(*argv);
7523785Sgusella 		if (hp == NULL) {
7623785Sgusella 			printf("%s: unknown host\n", *argv);
7723785Sgusella 			continue;
7823785Sgusella 		}
7923785Sgusella 		server.sin_family = hp->h_addrtype;
8023785Sgusella 		bcopy(hp->h_addr, &(server.sin_addr.s_addr), hp->h_length);
8127239Sbloom 		ack.tv_sec = 10;
8227239Sbloom 		ack.tv_usec = 0;
8327239Sbloom 		if ((measure_status = measure(&ack, &server)) < 0) {
8423785Sgusella 			perror("measure");
8523785Sgusella 			return;
8623785Sgusella 		}
8723785Sgusella 		switch (measure_status) {
8823785Sgusella 
8923785Sgusella 		case HOSTDOWN:
9023785Sgusella 			printf("%s is down\n", hp->h_name);
9123785Sgusella 			continue;
9223785Sgusella 			break;
9323785Sgusella 		case NONSTDTIME:
9423785Sgusella 			printf("%s time transmitted in a non-standard format\n",						 hp->h_name);
9523785Sgusella 			continue;
9623785Sgusella 			break;
9723785Sgusella 		case UNREACHABLE:
9823785Sgusella 			printf("%s is unreachable\n", hp->h_name);
9923785Sgusella 			continue;
10023785Sgusella 			break;
10123785Sgusella 		default:
10223785Sgusella 			break;
10323785Sgusella 		}
10423785Sgusella 
10523785Sgusella 		if (measure_delta > 0)
10623785Sgusella 			printf("time on %s is %d ms. ahead of time on %s\n",
10723785Sgusella 						hp->h_name, measure_delta,
10823785Sgusella 						hostname);
10923785Sgusella 		else
11023785Sgusella 			if (measure_delta == 0)
11123785Sgusella 		      		printf("%s and %s have the same time\n",
11223785Sgusella 						hp->h_name, hostname);
11323785Sgusella 			else
11423785Sgusella 		      	     printf("time on %s is %d ms. behind time on %s\n",
11523785Sgusella 					hp->h_name, -measure_delta, hostname);
11623785Sgusella 	}
11723785Sgusella 	return;
11823785Sgusella }
11923785Sgusella /*
12023785Sgusella  * finds location of master timedaemon
12123785Sgusella  */
12223785Sgusella 
12323785Sgusella msite(argc)
12423785Sgusella int argc;
12523785Sgusella {
12623785Sgusella 	int length;
12725578Sbloom 	int cc;
12825578Sbloom 	fd_set ready;
12923785Sgusella 	struct sockaddr_in dest;
13023785Sgusella 	struct timeval tout;
13123785Sgusella 	struct sockaddr_in from;
13223785Sgusella 	struct tsp msg;
13323785Sgusella 	struct servent *srvp;
13423785Sgusella 
13523785Sgusella 	if (argc != 1) {
13623785Sgusella 		printf("Usage: msite\n");
13723785Sgusella 		return;
13823785Sgusella 	}
13923785Sgusella 
14023785Sgusella 	srvp = getservbyname("timed", "udp");
14123785Sgusella 	if (srvp == 0) {
14223785Sgusella 		fprintf(stderr, "udp/timed: unknown service\n");
14323785Sgusella 		return;
14423785Sgusella 	}
14523785Sgusella 	dest.sin_port = srvp->s_port;
14623785Sgusella 	dest.sin_family = AF_INET;
14723785Sgusella 
14823785Sgusella 	(void)gethostname(hostname,sizeof(hostname));
14923785Sgusella 	hp = gethostbyname(hostname);
15023785Sgusella 	if (hp == NULL) {
15123785Sgusella 		perror("gethostbyname");
15223785Sgusella 		return;
15323785Sgusella 	}
15423785Sgusella 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
15523785Sgusella 
15623785Sgusella 	(void)strcpy(msg.tsp_name, hostname);
15723785Sgusella 	msg.tsp_type = TSP_MSITE;
15823785Sgusella 	msg.tsp_vers = TSPVERSION;
15923785Sgusella 	bytenetorder(&msg);
16023785Sgusella 	length = sizeof(struct sockaddr_in);
16123785Sgusella 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
16223785Sgusella 						&dest, length) < 0) {
16323785Sgusella 		perror("sendto");
16423785Sgusella 		return;
16523785Sgusella 	}
16623785Sgusella 
16723785Sgusella 	tout.tv_sec = 15;
16823785Sgusella 	tout.tv_usec = 0;
16925578Sbloom 	FD_ZERO(&ready);
17025578Sbloom 	FD_SET(sock, &ready);
17125578Sbloom 	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
17223785Sgusella 		length = sizeof(struct sockaddr_in);
17323785Sgusella 		cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0,
17423785Sgusella 							&from, &length);
17523785Sgusella 		if (cc < 0) {
17623785Sgusella 			perror("recvfrom");
17723785Sgusella 			return;
17823785Sgusella 		}
17923785Sgusella 		bytehostorder(&msg);
18023785Sgusella 		if (msg.tsp_type == TSP_ACK)
18123785Sgusella 			printf("master timedaemon runs on %s\n", msg.tsp_name);
18223785Sgusella 		else
18323785Sgusella 			printf("received wrong ack: %s\n",
18423785Sgusella 						tsptype[msg.tsp_type]);
18523785Sgusella 	} else
18623785Sgusella 		printf("communication error\n");
18723785Sgusella }
18823785Sgusella 
18923785Sgusella /*
19023785Sgusella  * quits timedc
19123785Sgusella  */
19223785Sgusella 
19323785Sgusella quit()
19423785Sgusella {
19523785Sgusella 	exit(0);
19623785Sgusella }
19723785Sgusella 
19823785Sgusella #define MAXH	4	/* max no. of hosts where election can occur */
19923785Sgusella 
20023785Sgusella /*
20123785Sgusella  * Causes the election timer to expire on the selected hosts
20223785Sgusella  * It sends just one udp message per machine, relying on
20323785Sgusella  * reliability of communication channel.
20423785Sgusella  */
20523785Sgusella 
20623785Sgusella testing(argc, argv)
20723785Sgusella int argc;
20823785Sgusella char *argv[];
20923785Sgusella {
21023785Sgusella 	int length;
21123785Sgusella 	int nhosts;
21223785Sgusella 	struct servent *srvp;
21323785Sgusella 	struct sockaddr_in sin[MAXH];
21423785Sgusella 	struct tsp msg;
21523785Sgusella 
21623785Sgusella 	if(argc < 2)  {
21723785Sgusella 		printf("Usage: testing host ...\n");
21823785Sgusella 		return;
21923785Sgusella 	}
22023785Sgusella 
22123785Sgusella 	srvp = getservbyname("timed", "udp");
22223785Sgusella 	if (srvp == 0) {
22323785Sgusella 		fprintf(stderr, "udp/timed: unknown service\n");
22423785Sgusella 		return;
22523785Sgusella 	}
22623785Sgusella 
22723785Sgusella 	nhosts = 0;
22823785Sgusella 	while (argc > 1) {
22923785Sgusella 		argc--; argv++;
23023785Sgusella 		hp = gethostbyname(*argv);
23123785Sgusella 		if (hp == NULL) {
23230101Sbostic 			printf("%s: unknown host\n", *argv);
23323785Sgusella 			argc--; argv++;
23423785Sgusella 			continue;
23523785Sgusella 		}
23623785Sgusella 		sin[nhosts].sin_port = srvp->s_port;
23723785Sgusella 		sin[nhosts].sin_family = hp->h_addrtype;
23823785Sgusella 		bcopy(hp->h_addr, &(sin[nhosts].sin_addr.s_addr), hp->h_length);
23923785Sgusella 		if (++nhosts == MAXH)
24023785Sgusella 			break;
24123785Sgusella 	}
24223785Sgusella 
24323785Sgusella 	msg.tsp_type = TSP_TEST;
24423785Sgusella 	msg.tsp_vers = TSPVERSION;
24523785Sgusella 	(void)gethostname(hostname, sizeof(hostname));
24623785Sgusella 	(void)strcpy(msg.tsp_name, hostname);
24723785Sgusella 	bytenetorder(&msg);	/* it is not really necessary here */
24823785Sgusella 	while (nhosts-- > 0) {
24923785Sgusella 		length = sizeof(struct sockaddr_in);
25023785Sgusella 		if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
25123785Sgusella 						&sin[nhosts], length) < 0) {
25223785Sgusella 			perror("sendto");
25323785Sgusella 			return;
25423785Sgusella 		}
25523785Sgusella 	}
25623785Sgusella }
25723785Sgusella 
25823785Sgusella /*
25923785Sgusella  * Enables or disables tracing on local timedaemon
26023785Sgusella  */
26123785Sgusella 
26223785Sgusella tracing(argc, argv)
26323785Sgusella int argc;
26423785Sgusella char *argv[];
26523785Sgusella {
26623785Sgusella 	int onflag;
26723785Sgusella 	int length;
26825578Sbloom 	int cc;
26925578Sbloom 	fd_set ready;
27023785Sgusella 	struct sockaddr_in dest;
27123785Sgusella 	struct timeval tout;
27223785Sgusella 	struct sockaddr_in from;
27323785Sgusella 	struct tsp msg;
27423785Sgusella 	struct servent *srvp;
27523785Sgusella 
27623785Sgusella 	if (argc != 2) {
27723785Sgusella 		printf("Usage: tracing { on | off }\n");
27823785Sgusella 		return;
27923785Sgusella 	}
28023785Sgusella 
28123785Sgusella 	srvp = getservbyname("timed", "udp");
28223785Sgusella 	if (srvp == 0) {
28323785Sgusella 		fprintf(stderr, "udp/timed: unknown service\n");
28423785Sgusella 		return;
28523785Sgusella 	}
28623785Sgusella 	dest.sin_port = srvp->s_port;
28723785Sgusella 	dest.sin_family = AF_INET;
28823785Sgusella 
28923785Sgusella 	(void)gethostname(hostname,sizeof(hostname));
29023785Sgusella 	hp = gethostbyname(hostname);
29123785Sgusella 	bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length);
29223785Sgusella 
29323785Sgusella 	if (strcmp(argv[1], "on") == 0) {
29423785Sgusella 		msg.tsp_type = TSP_TRACEON;
29523785Sgusella 		onflag = ON;
29623785Sgusella 	} else {
29723785Sgusella 		msg.tsp_type = TSP_TRACEOFF;
29823785Sgusella 		onflag = OFF;
29923785Sgusella 	}
30023785Sgusella 
30123785Sgusella 	(void)strcpy(msg.tsp_name, hostname);
30223785Sgusella 	msg.tsp_vers = TSPVERSION;
30323785Sgusella 	bytenetorder(&msg);
30423785Sgusella 	length = sizeof(struct sockaddr_in);
30523785Sgusella 	if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0,
30623785Sgusella 						&dest, length) < 0) {
30723785Sgusella 		perror("sendto");
30823785Sgusella 		return;
30923785Sgusella 	}
31023785Sgusella 
31123785Sgusella 	tout.tv_sec = 5;
31223785Sgusella 	tout.tv_usec = 0;
31325578Sbloom 	FD_ZERO(&ready);
31425578Sbloom 	FD_SET(sock, &ready);
31525578Sbloom 	if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
31623785Sgusella 		length = sizeof(struct sockaddr_in);
31723785Sgusella 		cc = recvfrom(sock, (char *)&msg, sizeof(struct tsp), 0,
31823785Sgusella 							&from, &length);
31923785Sgusella 		if (cc < 0) {
32023785Sgusella 			perror("recvfrom");
32123785Sgusella 			return;
32223785Sgusella 		}
32323785Sgusella 		bytehostorder(&msg);
32423785Sgusella 		if (msg.tsp_type == TSP_ACK)
32523785Sgusella 			if (onflag)
32623785Sgusella 				printf("timed tracing enabled\n");
32723785Sgusella 			else
32823785Sgusella 				printf("timed tracing disabled\n");
32923785Sgusella 		else
33023785Sgusella 			printf("wrong ack received: %s\n",
33123785Sgusella 						tsptype[msg.tsp_type]);
33223785Sgusella 	} else
33323785Sgusella 		printf("communication error\n");
33423785Sgusella }
33523785Sgusella 
33623785Sgusella priv_resources()
33723785Sgusella {
33823785Sgusella 	int port;
33923785Sgusella 	struct sockaddr_in sin;
34023785Sgusella 
34123785Sgusella 	sock = socket(AF_INET, SOCK_DGRAM, 0);
34223785Sgusella 	if (sock < 0) {
34323785Sgusella 		perror("opening socket");
34423785Sgusella 		return(-1);
34523785Sgusella 	}
34623785Sgusella 
34723785Sgusella 	sin.sin_family = AF_INET;
34823785Sgusella 	sin.sin_addr.s_addr = 0;
34923785Sgusella 	for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
35023785Sgusella 		sin.sin_port = htons((u_short)port);
35123785Sgusella 		if (bind(sock, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
35223785Sgusella 			break;
35323785Sgusella 		if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
35423785Sgusella 			perror("bind");
35523785Sgusella 			(void) close(sock);
35623785Sgusella 			return(-1);
35723785Sgusella 		}
35823785Sgusella 	}
35923785Sgusella 	if (port == IPPORT_RESERVED / 2) {
36023785Sgusella 		fprintf(stderr, "all reserved ports in use\n");
36123785Sgusella 		(void) close(sock);
36223785Sgusella 		return(-1);
36323785Sgusella 	}
36423785Sgusella 
36523785Sgusella 	sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
36623785Sgusella 	if (sock_raw < 0)  {
36723785Sgusella 		perror("opening raw socket");
36823785Sgusella 		(void) close(sock_raw);
36923785Sgusella 		return(-1);
37023785Sgusella 	}
37123785Sgusella 	return(1);
37223785Sgusella }
373