159906Sbostic /*- 2*61885Sbostic * Copyright (c) 1985, 1993 3*61885Sbostic * The Regents of the University of California. All rights reserved. 433123Sbostic * 542829Sbostic * %sccs.include.redist.c% 623785Sgusella */ 723785Sgusella 823785Sgusella #ifndef lint 9*61885Sbostic static char sccsid[] = "@(#)cmds.c 8.1 (Berkeley) 06/06/93"; 1033123Sbostic #endif /* not lint */ 1123785Sgusella 1259906Sbostic #ifdef sgi 1359906Sbostic #ident "$Revision: 1.10 $" 1459906Sbostic #endif 1559906Sbostic 1623785Sgusella #include "timedc.h" 1759906Sbostic #include <sys/file.h> 1859906Sbostic 1923785Sgusella #include <netinet/in_systm.h> 2023785Sgusella #include <netinet/ip.h> 2123785Sgusella #include <netinet/ip_icmp.h> 2259906Sbostic 2359906Sbostic #include <stdlib.h> 2459906Sbostic #include <strings.h> 2559906Sbostic #include <unistd.h> 2659906Sbostic 2723785Sgusella #define TSPTYPES 2823785Sgusella #include <protocols/timed.h> 2923785Sgusella 3059906Sbostic #ifdef sgi 3159906Sbostic #include <bstring.h> 3259906Sbostic #include <sys/clock.h> 3359906Sbostic #else 3459906Sbostic #define SECHR (60*60) 3559906Sbostic #define SECDAY (24*SECHR) 3659906Sbostic #endif /* sgi */ 3759906Sbostic 3859906Sbostic # define DATE_PROTO "udp" 3959906Sbostic # define DATE_PORT "time" 4059906Sbostic 4159906Sbostic 4223785Sgusella int sock; 4323785Sgusella int sock_raw; 4459906Sbostic char myname[MAXHOSTNAMELEN]; 4559906Sbostic struct hostent *hp; 4623785Sgusella struct sockaddr_in server; 4759906Sbostic struct sockaddr_in dayaddr; 4823785Sgusella extern int measure_delta; 4923785Sgusella 5059906Sbostic void bytenetorder(struct tsp *); 5159906Sbostic void bytehostorder(struct tsp *); 5259906Sbostic 5359906Sbostic 5459906Sbostic #define BU ((unsigned long)2208988800) /* seconds before UNIX epoch */ 5559906Sbostic 5659906Sbostic 5759906Sbostic /* compute the difference between our date and another machine 5859906Sbostic */ 5959906Sbostic static int /* difference in days from our time */ 6059906Sbostic daydiff(hostname) 6159906Sbostic char *hostname; 6259906Sbostic { 6359906Sbostic int i; 6459906Sbostic int trials; 6559906Sbostic struct timeval tout, now; 6659906Sbostic fd_set ready; 6759906Sbostic struct sockaddr from; 6859906Sbostic int fromlen; 6959906Sbostic unsigned long sec; 7059906Sbostic 7159906Sbostic 7259906Sbostic /* wait 2 seconds between 10 tries */ 7359906Sbostic tout.tv_sec = 2; 7459906Sbostic tout.tv_usec = 0; 7559906Sbostic for (trials = 0; trials < 10; trials++) { 7659906Sbostic /* ask for the time */ 7759906Sbostic sec = 0; 7859906Sbostic if (sendto(sock, &sec, sizeof(sec), 0, 7959906Sbostic (struct sockaddr*)&dayaddr, sizeof(dayaddr)) < 0) { 8059906Sbostic perror("sendto(sock)"); 8159906Sbostic return 0; 8259906Sbostic } 8359906Sbostic 8459906Sbostic for (;;) { 8559906Sbostic FD_ZERO(&ready); 8659906Sbostic FD_SET(sock, &ready); 8759906Sbostic i = select(sock+1, &ready, (fd_set *)0, 8859906Sbostic (fd_set *)0, &tout); 8959906Sbostic if (i < 0) { 9059906Sbostic if (errno = EINTR) 9159906Sbostic continue; 9259906Sbostic perror("select(date read)"); 9359906Sbostic return 0; 9459906Sbostic } 9559906Sbostic if (0 == i) 9659906Sbostic break; 9759906Sbostic 9859906Sbostic fromlen = sizeof(from); 9959906Sbostic if (recvfrom(sock,&sec,sizeof(sec),0, 10059906Sbostic &from,&fromlen) < 0) { 10159906Sbostic perror("recvfrom(date read)"); 10259906Sbostic return 0; 10359906Sbostic } 10459906Sbostic 10559906Sbostic sec = ntohl(sec); 10659906Sbostic if (sec < BU) { 10759906Sbostic fprintf(stderr, 10859906Sbostic "%s says it is before 1970: %lu", 10959906Sbostic hostname, sec); 11059906Sbostic return 0; 11159906Sbostic } 11259906Sbostic sec -= BU; 11359906Sbostic 11459906Sbostic (void)gettimeofday(&now, (struct timezone*)0); 11559906Sbostic return (sec - now.tv_sec); 11659906Sbostic } 11759906Sbostic } 11859906Sbostic 11959906Sbostic /* if we get here, we tried too many times */ 12059906Sbostic fprintf(stderr,"%s will not tell us the date\n", hostname); 12159906Sbostic return 0; 12259906Sbostic } 12359906Sbostic 12459906Sbostic 12523785Sgusella /* 12659906Sbostic * Clockdiff computes the difference between the time of the machine on 12723785Sgusella * which it is called and the time of the machines given as argument. 12823785Sgusella * The time differences measured by clockdiff are obtained using a sequence 12923785Sgusella * of ICMP TSTAMP messages which are returned to the sender by the IP module 13023785Sgusella * in the remote machine. 13159906Sbostic * In order to compare clocks of machines in different time zones, the time 13259906Sbostic * is transmitted (as a 32-bit value) in milliseconds since midnight UT. 13323785Sgusella * If a hosts uses a different time format, it should set the high order 13423785Sgusella * bit of the 32-bit quantity it transmits. 13523785Sgusella * However, VMS apparently transmits the time in milliseconds since midnight 13659906Sbostic * local time (rather than GMT) without setting the high order bit. 13759906Sbostic * Furthermore, it does not understand daylight-saving time. This makes 13823785Sgusella * clockdiff behaving inconsistently with hosts running VMS. 13923785Sgusella * 14059906Sbostic * In order to reduce the sensitivity to the variance of message transmission 14159906Sbostic * time, clockdiff sends a sequence of messages. Yet, measures between 14259906Sbostic * two `distant' hosts can be affected by a small error. The error can, 14359906Sbostic * however, be reduced by increasing the number of messages sent in each 14459906Sbostic * measurement. 14523785Sgusella */ 14659906Sbostic void 14723785Sgusella clockdiff(argc, argv) 14859906Sbostic int argc; 14959906Sbostic char *argv[]; 15023785Sgusella { 15123785Sgusella int measure_status; 15259906Sbostic extern int measure(u_long, u_long, char *, struct sockaddr_in*, int); 15359906Sbostic register int avg_cnt; 15459906Sbostic register long avg; 15559906Sbostic struct servent *sp; 15623785Sgusella 15759906Sbostic if (argc < 2) { 15823785Sgusella printf("Usage: clockdiff host ... \n"); 15923785Sgusella return; 16023785Sgusella } 16123785Sgusella 16259906Sbostic (void)gethostname(myname,sizeof(myname)); 16323785Sgusella 16459906Sbostic /* get the address for the date ready */ 16559906Sbostic sp = getservbyname(DATE_PORT, DATE_PROTO); 16659906Sbostic if (!sp) { 16759906Sbostic (void)fprintf(stderr, "%s/%s is an unknown service\n", 16859906Sbostic DATE_PORT, DATE_PROTO); 16959906Sbostic dayaddr.sin_port = 0; 17059906Sbostic } else { 17159906Sbostic dayaddr.sin_port = sp->s_port; 17259906Sbostic } 17359906Sbostic 17423785Sgusella while (argc > 1) { 17523785Sgusella argc--; argv++; 17623785Sgusella hp = gethostbyname(*argv); 17723785Sgusella if (hp == NULL) { 17859906Sbostic fprintf(stderr, "timedc: %s: ", *argv); 17959906Sbostic herror(0); 18023785Sgusella continue; 18123785Sgusella } 18259906Sbostic 18323785Sgusella server.sin_family = hp->h_addrtype; 18459906Sbostic bcopy(hp->h_addr, &server.sin_addr.s_addr, hp->h_length); 18559906Sbostic for (avg_cnt = 0, avg = 0; avg_cnt < 16; avg_cnt++) { 18659906Sbostic measure_status = measure(10000,100, *argv, &server, 1); 18759906Sbostic if (measure_status != GOOD) 18859906Sbostic break; 18959906Sbostic avg += measure_delta; 19023785Sgusella } 19159906Sbostic if (measure_status == GOOD) 19259906Sbostic measure_delta = avg/avg_cnt; 19359906Sbostic 19423785Sgusella switch (measure_status) { 19523785Sgusella case HOSTDOWN: 19623785Sgusella printf("%s is down\n", hp->h_name); 19723785Sgusella continue; 19823785Sgusella case NONSTDTIME: 19959906Sbostic printf("%s transmitts a non-standard time format\n", 20059906Sbostic hp->h_name); 20123785Sgusella continue; 20223785Sgusella case UNREACHABLE: 20323785Sgusella printf("%s is unreachable\n", hp->h_name); 20423785Sgusella continue; 20523785Sgusella } 20623785Sgusella 20759906Sbostic /* 20859906Sbostic * Try to get the date only after using ICMP timestamps to 20959906Sbostic * get the time. This is because the date protocol 21059906Sbostic * is optional. 21159906Sbostic */ 21259906Sbostic if (dayaddr.sin_port != 0) { 21359906Sbostic dayaddr.sin_family = hp->h_addrtype; 21459906Sbostic bcopy(hp->h_addr, &dayaddr.sin_addr.s_addr, 21559906Sbostic hp->h_length); 21659906Sbostic avg = daydiff(*argv); 21759906Sbostic if (avg > SECDAY) { 21859906Sbostic printf("time on %s is %ld days ahead %s\n", 21959906Sbostic hp->h_name, avg/SECDAY, myname); 22059906Sbostic continue; 22159906Sbostic } else if (avg < -SECDAY) { 22259906Sbostic printf("time on %s is %ld days behind %s\n", 22359906Sbostic hp->h_name, -avg/SECDAY, myname); 22459906Sbostic continue; 22559906Sbostic } 22659906Sbostic } 22759906Sbostic 22859906Sbostic if (measure_delta > 0) { 22959906Sbostic printf("time on %s is %d ms. ahead of time on %s\n", 23059906Sbostic hp->h_name, measure_delta, myname); 23159906Sbostic } else if (measure_delta == 0) { 23259906Sbostic printf("%s and %s have the same time\n", 23359906Sbostic hp->h_name, myname); 23459906Sbostic } else { 23559906Sbostic printf("time on %s is %d ms. behind time on %s\n", 23659906Sbostic hp->h_name, -measure_delta, myname); 23759906Sbostic } 23823785Sgusella } 23923785Sgusella return; 24023785Sgusella } 24159906Sbostic 24259906Sbostic 24323785Sgusella /* 24423785Sgusella * finds location of master timedaemon 24523785Sgusella */ 24659906Sbostic void 24759906Sbostic msite(argc, argv) 24859906Sbostic int argc; 24959906Sbostic char *argv[]; 25023785Sgusella { 25125578Sbloom int cc; 25225578Sbloom fd_set ready; 25323785Sgusella struct sockaddr_in dest; 25459906Sbostic int i, length; 25559906Sbostic struct sockaddr from; 25623785Sgusella struct timeval tout; 25723785Sgusella struct tsp msg; 25823785Sgusella struct servent *srvp; 25959906Sbostic char *tgtname; 26023785Sgusella 26159906Sbostic if (argc < 1) { 26259906Sbostic printf("Usage: msite [hostname]\n"); 26323785Sgusella return; 26423785Sgusella } 26523785Sgusella 26623785Sgusella srvp = getservbyname("timed", "udp"); 26723785Sgusella if (srvp == 0) { 26823785Sgusella fprintf(stderr, "udp/timed: unknown service\n"); 26923785Sgusella return; 27035784Sbostic } 27123785Sgusella dest.sin_port = srvp->s_port; 27223785Sgusella dest.sin_family = AF_INET; 27323785Sgusella 27459906Sbostic (void)gethostname(myname, sizeof(myname)); 27559906Sbostic i = 1; 27659906Sbostic do { 27759906Sbostic tgtname = (i >= argc) ? myname : argv[i]; 27859906Sbostic hp = gethostbyname(tgtname); 27959906Sbostic if (hp == 0) { 28059906Sbostic fprintf(stderr, "timedc: %s: ", tgtname); 28159906Sbostic herror(0); 28259906Sbostic continue; 28359906Sbostic } 28459906Sbostic bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 28523785Sgusella 28659906Sbostic (void)strcpy(msg.tsp_name, myname); 28759906Sbostic msg.tsp_type = TSP_MSITE; 28859906Sbostic msg.tsp_vers = TSPVERSION; 28959906Sbostic bytenetorder(&msg); 29059906Sbostic if (sendto(sock, &msg, sizeof(struct tsp), 0, 29159906Sbostic (struct sockaddr*)&dest, 29259906Sbostic sizeof(struct sockaddr)) < 0) { 29359906Sbostic perror("sendto"); 29459906Sbostic continue; 29559906Sbostic } 29623785Sgusella 29759906Sbostic tout.tv_sec = 15; 29859906Sbostic tout.tv_usec = 0; 29959906Sbostic FD_ZERO(&ready); 30059906Sbostic FD_SET(sock, &ready); 30159906Sbostic if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, 30259906Sbostic &tout)) { 30359906Sbostic length = sizeof(struct sockaddr); 30459906Sbostic cc = recvfrom(sock, &msg, sizeof(struct tsp), 0, 30559906Sbostic &from, &length); 30659906Sbostic if (cc < 0) { 30759906Sbostic perror("recvfrom"); 30859906Sbostic continue; 30959906Sbostic } 31059906Sbostic bytehostorder(&msg); 31159906Sbostic if (msg.tsp_type == TSP_ACK) { 31259906Sbostic printf("master timedaemon at %s is %s\n", 31359906Sbostic tgtname, msg.tsp_name); 31459906Sbostic } else { 31559906Sbostic printf("received wrong ack: %s\n", 31659906Sbostic tsptype[msg.tsp_type]); 31759906Sbostic } 31859906Sbostic } else { 31959906Sbostic printf("communication error with %s\n", tgtname); 32023785Sgusella } 32159906Sbostic } while (++i < argc); 32223785Sgusella } 32323785Sgusella 32423785Sgusella /* 32523785Sgusella * quits timedc 32623785Sgusella */ 32759906Sbostic void 32823785Sgusella quit() 32923785Sgusella { 33023785Sgusella exit(0); 33123785Sgusella } 33223785Sgusella 33323785Sgusella 33423785Sgusella /* 33523785Sgusella * Causes the election timer to expire on the selected hosts 33623785Sgusella * It sends just one udp message per machine, relying on 33723785Sgusella * reliability of communication channel. 33823785Sgusella */ 33959906Sbostic void 34023785Sgusella testing(argc, argv) 34159906Sbostic int argc; 34259906Sbostic char *argv[]; 34323785Sgusella { 34423785Sgusella struct servent *srvp; 34559906Sbostic struct sockaddr_in sin; 34623785Sgusella struct tsp msg; 34723785Sgusella 34859906Sbostic if (argc < 2) { 34959906Sbostic printf("Usage: election host1 [host2 ...]\n"); 35023785Sgusella return; 35123785Sgusella } 35223785Sgusella 35323785Sgusella srvp = getservbyname("timed", "udp"); 35423785Sgusella if (srvp == 0) { 35523785Sgusella fprintf(stderr, "udp/timed: unknown service\n"); 35623785Sgusella return; 35759906Sbostic } 35823785Sgusella 35923785Sgusella while (argc > 1) { 36023785Sgusella argc--; argv++; 36123785Sgusella hp = gethostbyname(*argv); 36223785Sgusella if (hp == NULL) { 36359906Sbostic fprintf(stderr, "timedc: %s: ", *argv); 36459906Sbostic herror(0); 36523785Sgusella argc--; argv++; 36623785Sgusella continue; 36723785Sgusella } 36859906Sbostic sin.sin_port = srvp->s_port; 36959906Sbostic sin.sin_family = hp->h_addrtype; 37059906Sbostic bcopy(hp->h_addr, &sin.sin_addr.s_addr, hp->h_length); 37123785Sgusella 37259906Sbostic msg.tsp_type = TSP_TEST; 37359906Sbostic msg.tsp_vers = TSPVERSION; 37459906Sbostic (void)gethostname(myname, sizeof(myname)); 37559906Sbostic (void)strncpy(msg.tsp_name, myname, sizeof(msg.tsp_name)); 37659906Sbostic bytenetorder(&msg); 37759906Sbostic if (sendto(sock, &msg, sizeof(struct tsp), 0, 37859906Sbostic (struct sockaddr*)&sin, 37959906Sbostic sizeof(struct sockaddr)) < 0) { 38023785Sgusella perror("sendto"); 38123785Sgusella } 38223785Sgusella } 38323785Sgusella } 38423785Sgusella 38559906Sbostic 38623785Sgusella /* 38723785Sgusella * Enables or disables tracing on local timedaemon 38823785Sgusella */ 38959906Sbostic void 39023785Sgusella tracing(argc, argv) 39159906Sbostic int argc; 39259906Sbostic char *argv[]; 39323785Sgusella { 39423785Sgusella int onflag; 39523785Sgusella int length; 39625578Sbloom int cc; 39725578Sbloom fd_set ready; 39823785Sgusella struct sockaddr_in dest; 39959906Sbostic struct sockaddr from; 40023785Sgusella struct timeval tout; 40123785Sgusella struct tsp msg; 40223785Sgusella struct servent *srvp; 40323785Sgusella 40423785Sgusella if (argc != 2) { 40523785Sgusella printf("Usage: tracing { on | off }\n"); 40623785Sgusella return; 40723785Sgusella } 40823785Sgusella 40923785Sgusella srvp = getservbyname("timed", "udp"); 41023785Sgusella if (srvp == 0) { 41123785Sgusella fprintf(stderr, "udp/timed: unknown service\n"); 41223785Sgusella return; 41359906Sbostic } 41423785Sgusella dest.sin_port = srvp->s_port; 41523785Sgusella dest.sin_family = AF_INET; 41623785Sgusella 41759906Sbostic (void)gethostname(myname,sizeof(myname)); 41859906Sbostic hp = gethostbyname(myname); 41923785Sgusella bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 42023785Sgusella 42123785Sgusella if (strcmp(argv[1], "on") == 0) { 42223785Sgusella msg.tsp_type = TSP_TRACEON; 42323785Sgusella onflag = ON; 42423785Sgusella } else { 42523785Sgusella msg.tsp_type = TSP_TRACEOFF; 42623785Sgusella onflag = OFF; 42723785Sgusella } 42823785Sgusella 42959906Sbostic (void)strcpy(msg.tsp_name, myname); 43023785Sgusella msg.tsp_vers = TSPVERSION; 43123785Sgusella bytenetorder(&msg); 43259906Sbostic if (sendto(sock, &msg, sizeof(struct tsp), 0, 43359906Sbostic (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) { 43423785Sgusella perror("sendto"); 43523785Sgusella return; 43623785Sgusella } 43723785Sgusella 43823785Sgusella tout.tv_sec = 5; 43923785Sgusella tout.tv_usec = 0; 44025578Sbloom FD_ZERO(&ready); 44125578Sbloom FD_SET(sock, &ready); 44225578Sbloom if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { 44359906Sbostic length = sizeof(struct sockaddr); 44459906Sbostic cc = recvfrom(sock, &msg, sizeof(struct tsp), 0, 44559906Sbostic &from, &length); 44623785Sgusella if (cc < 0) { 44723785Sgusella perror("recvfrom"); 44823785Sgusella return; 44923785Sgusella } 45023785Sgusella bytehostorder(&msg); 45123785Sgusella if (msg.tsp_type == TSP_ACK) 45223785Sgusella if (onflag) 45323785Sgusella printf("timed tracing enabled\n"); 45423785Sgusella else 45523785Sgusella printf("timed tracing disabled\n"); 45623785Sgusella else 45759906Sbostic printf("wrong ack received: %s\n", 45823785Sgusella tsptype[msg.tsp_type]); 45923785Sgusella } else 46023785Sgusella printf("communication error\n"); 46123785Sgusella } 46223785Sgusella 46359906Sbostic int 46423785Sgusella priv_resources() 46523785Sgusella { 46623785Sgusella int port; 46723785Sgusella struct sockaddr_in sin; 46823785Sgusella 46923785Sgusella sock = socket(AF_INET, SOCK_DGRAM, 0); 47023785Sgusella if (sock < 0) { 47123785Sgusella perror("opening socket"); 47223785Sgusella return(-1); 47323785Sgusella } 47423785Sgusella 47523785Sgusella sin.sin_family = AF_INET; 47623785Sgusella sin.sin_addr.s_addr = 0; 47723785Sgusella for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { 47823785Sgusella sin.sin_port = htons((u_short)port); 47959906Sbostic if (bind(sock, (struct sockaddr*)&sin, sizeof (sin)) >= 0) 48023785Sgusella break; 48123785Sgusella if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) { 48223785Sgusella perror("bind"); 48323785Sgusella (void) close(sock); 48423785Sgusella return(-1); 48523785Sgusella } 48623785Sgusella } 48723785Sgusella if (port == IPPORT_RESERVED / 2) { 48823785Sgusella fprintf(stderr, "all reserved ports in use\n"); 48923785Sgusella (void) close(sock); 49023785Sgusella return(-1); 49123785Sgusella } 49223785Sgusella 49359906Sbostic sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 49423785Sgusella if (sock_raw < 0) { 49523785Sgusella perror("opening raw socket"); 49659906Sbostic (void) close(sock); 49723785Sgusella return(-1); 49823785Sgusella } 49923785Sgusella return(1); 50023785Sgusella } 501