1*59906Sbostic /*- 2*59906Sbostic * Copyright (c) 1985, 1993 The Regents of the University of California. 333123Sbostic * All rights reserved. 433123Sbostic * 542829Sbostic * %sccs.include.redist.c% 623785Sgusella */ 723785Sgusella 823785Sgusella #ifndef lint 9*59906Sbostic static char sccsid[] = "@(#)cmds.c 5.1 (Berkeley) 05/11/93"; 1033123Sbostic #endif /* not lint */ 1123785Sgusella 12*59906Sbostic #ifdef sgi 13*59906Sbostic #ident "$Revision: 1.10 $" 14*59906Sbostic #endif 15*59906Sbostic 1623785Sgusella #include "timedc.h" 17*59906Sbostic #include <sys/file.h> 18*59906Sbostic 1923785Sgusella #include <netinet/in_systm.h> 2023785Sgusella #include <netinet/ip.h> 2123785Sgusella #include <netinet/ip_icmp.h> 22*59906Sbostic 23*59906Sbostic #include <stdlib.h> 24*59906Sbostic #include <strings.h> 25*59906Sbostic #include <unistd.h> 26*59906Sbostic 2723785Sgusella #define TSPTYPES 2823785Sgusella #include <protocols/timed.h> 2923785Sgusella 30*59906Sbostic #ifdef sgi 31*59906Sbostic #include <bstring.h> 32*59906Sbostic #include <sys/clock.h> 33*59906Sbostic #else 34*59906Sbostic #define SECHR (60*60) 35*59906Sbostic #define SECDAY (24*SECHR) 36*59906Sbostic #endif /* sgi */ 37*59906Sbostic 38*59906Sbostic # define DATE_PROTO "udp" 39*59906Sbostic # define DATE_PORT "time" 40*59906Sbostic 41*59906Sbostic 4223785Sgusella int sock; 4323785Sgusella int sock_raw; 44*59906Sbostic char myname[MAXHOSTNAMELEN]; 45*59906Sbostic struct hostent *hp; 4623785Sgusella struct sockaddr_in server; 47*59906Sbostic struct sockaddr_in dayaddr; 4823785Sgusella extern int measure_delta; 4923785Sgusella 50*59906Sbostic void bytenetorder(struct tsp *); 51*59906Sbostic void bytehostorder(struct tsp *); 52*59906Sbostic 53*59906Sbostic 54*59906Sbostic #define BU ((unsigned long)2208988800) /* seconds before UNIX epoch */ 55*59906Sbostic 56*59906Sbostic 57*59906Sbostic /* compute the difference between our date and another machine 58*59906Sbostic */ 59*59906Sbostic static int /* difference in days from our time */ 60*59906Sbostic daydiff(hostname) 61*59906Sbostic char *hostname; 62*59906Sbostic { 63*59906Sbostic int i; 64*59906Sbostic int trials; 65*59906Sbostic struct timeval tout, now; 66*59906Sbostic fd_set ready; 67*59906Sbostic struct sockaddr from; 68*59906Sbostic int fromlen; 69*59906Sbostic unsigned long sec; 70*59906Sbostic 71*59906Sbostic 72*59906Sbostic /* wait 2 seconds between 10 tries */ 73*59906Sbostic tout.tv_sec = 2; 74*59906Sbostic tout.tv_usec = 0; 75*59906Sbostic for (trials = 0; trials < 10; trials++) { 76*59906Sbostic /* ask for the time */ 77*59906Sbostic sec = 0; 78*59906Sbostic if (sendto(sock, &sec, sizeof(sec), 0, 79*59906Sbostic (struct sockaddr*)&dayaddr, sizeof(dayaddr)) < 0) { 80*59906Sbostic perror("sendto(sock)"); 81*59906Sbostic return 0; 82*59906Sbostic } 83*59906Sbostic 84*59906Sbostic for (;;) { 85*59906Sbostic FD_ZERO(&ready); 86*59906Sbostic FD_SET(sock, &ready); 87*59906Sbostic i = select(sock+1, &ready, (fd_set *)0, 88*59906Sbostic (fd_set *)0, &tout); 89*59906Sbostic if (i < 0) { 90*59906Sbostic if (errno = EINTR) 91*59906Sbostic continue; 92*59906Sbostic perror("select(date read)"); 93*59906Sbostic return 0; 94*59906Sbostic } 95*59906Sbostic if (0 == i) 96*59906Sbostic break; 97*59906Sbostic 98*59906Sbostic fromlen = sizeof(from); 99*59906Sbostic if (recvfrom(sock,&sec,sizeof(sec),0, 100*59906Sbostic &from,&fromlen) < 0) { 101*59906Sbostic perror("recvfrom(date read)"); 102*59906Sbostic return 0; 103*59906Sbostic } 104*59906Sbostic 105*59906Sbostic sec = ntohl(sec); 106*59906Sbostic if (sec < BU) { 107*59906Sbostic fprintf(stderr, 108*59906Sbostic "%s says it is before 1970: %lu", 109*59906Sbostic hostname, sec); 110*59906Sbostic return 0; 111*59906Sbostic } 112*59906Sbostic sec -= BU; 113*59906Sbostic 114*59906Sbostic (void)gettimeofday(&now, (struct timezone*)0); 115*59906Sbostic return (sec - now.tv_sec); 116*59906Sbostic } 117*59906Sbostic } 118*59906Sbostic 119*59906Sbostic /* if we get here, we tried too many times */ 120*59906Sbostic fprintf(stderr,"%s will not tell us the date\n", hostname); 121*59906Sbostic return 0; 122*59906Sbostic } 123*59906Sbostic 124*59906Sbostic 12523785Sgusella /* 126*59906Sbostic * 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. 131*59906Sbostic * In order to compare clocks of machines in different time zones, the time 132*59906Sbostic * 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 136*59906Sbostic * local time (rather than GMT) without setting the high order bit. 137*59906Sbostic * Furthermore, it does not understand daylight-saving time. This makes 13823785Sgusella * clockdiff behaving inconsistently with hosts running VMS. 13923785Sgusella * 140*59906Sbostic * In order to reduce the sensitivity to the variance of message transmission 141*59906Sbostic * time, clockdiff sends a sequence of messages. Yet, measures between 142*59906Sbostic * two `distant' hosts can be affected by a small error. The error can, 143*59906Sbostic * however, be reduced by increasing the number of messages sent in each 144*59906Sbostic * measurement. 14523785Sgusella */ 146*59906Sbostic void 14723785Sgusella clockdiff(argc, argv) 148*59906Sbostic int argc; 149*59906Sbostic char *argv[]; 15023785Sgusella { 15123785Sgusella int measure_status; 152*59906Sbostic extern int measure(u_long, u_long, char *, struct sockaddr_in*, int); 153*59906Sbostic register int avg_cnt; 154*59906Sbostic register long avg; 155*59906Sbostic struct servent *sp; 15623785Sgusella 157*59906Sbostic if (argc < 2) { 15823785Sgusella printf("Usage: clockdiff host ... \n"); 15923785Sgusella return; 16023785Sgusella } 16123785Sgusella 162*59906Sbostic (void)gethostname(myname,sizeof(myname)); 16323785Sgusella 164*59906Sbostic /* get the address for the date ready */ 165*59906Sbostic sp = getservbyname(DATE_PORT, DATE_PROTO); 166*59906Sbostic if (!sp) { 167*59906Sbostic (void)fprintf(stderr, "%s/%s is an unknown service\n", 168*59906Sbostic DATE_PORT, DATE_PROTO); 169*59906Sbostic dayaddr.sin_port = 0; 170*59906Sbostic } else { 171*59906Sbostic dayaddr.sin_port = sp->s_port; 172*59906Sbostic } 173*59906Sbostic 17423785Sgusella while (argc > 1) { 17523785Sgusella argc--; argv++; 17623785Sgusella hp = gethostbyname(*argv); 17723785Sgusella if (hp == NULL) { 178*59906Sbostic fprintf(stderr, "timedc: %s: ", *argv); 179*59906Sbostic herror(0); 18023785Sgusella continue; 18123785Sgusella } 182*59906Sbostic 18323785Sgusella server.sin_family = hp->h_addrtype; 184*59906Sbostic bcopy(hp->h_addr, &server.sin_addr.s_addr, hp->h_length); 185*59906Sbostic for (avg_cnt = 0, avg = 0; avg_cnt < 16; avg_cnt++) { 186*59906Sbostic measure_status = measure(10000,100, *argv, &server, 1); 187*59906Sbostic if (measure_status != GOOD) 188*59906Sbostic break; 189*59906Sbostic avg += measure_delta; 19023785Sgusella } 191*59906Sbostic if (measure_status == GOOD) 192*59906Sbostic measure_delta = avg/avg_cnt; 193*59906Sbostic 19423785Sgusella switch (measure_status) { 19523785Sgusella case HOSTDOWN: 19623785Sgusella printf("%s is down\n", hp->h_name); 19723785Sgusella continue; 19823785Sgusella case NONSTDTIME: 199*59906Sbostic printf("%s transmitts a non-standard time format\n", 200*59906Sbostic hp->h_name); 20123785Sgusella continue; 20223785Sgusella case UNREACHABLE: 20323785Sgusella printf("%s is unreachable\n", hp->h_name); 20423785Sgusella continue; 20523785Sgusella } 20623785Sgusella 207*59906Sbostic /* 208*59906Sbostic * Try to get the date only after using ICMP timestamps to 209*59906Sbostic * get the time. This is because the date protocol 210*59906Sbostic * is optional. 211*59906Sbostic */ 212*59906Sbostic if (dayaddr.sin_port != 0) { 213*59906Sbostic dayaddr.sin_family = hp->h_addrtype; 214*59906Sbostic bcopy(hp->h_addr, &dayaddr.sin_addr.s_addr, 215*59906Sbostic hp->h_length); 216*59906Sbostic avg = daydiff(*argv); 217*59906Sbostic if (avg > SECDAY) { 218*59906Sbostic printf("time on %s is %ld days ahead %s\n", 219*59906Sbostic hp->h_name, avg/SECDAY, myname); 220*59906Sbostic continue; 221*59906Sbostic } else if (avg < -SECDAY) { 222*59906Sbostic printf("time on %s is %ld days behind %s\n", 223*59906Sbostic hp->h_name, -avg/SECDAY, myname); 224*59906Sbostic continue; 225*59906Sbostic } 226*59906Sbostic } 227*59906Sbostic 228*59906Sbostic if (measure_delta > 0) { 229*59906Sbostic printf("time on %s is %d ms. ahead of time on %s\n", 230*59906Sbostic hp->h_name, measure_delta, myname); 231*59906Sbostic } else if (measure_delta == 0) { 232*59906Sbostic printf("%s and %s have the same time\n", 233*59906Sbostic hp->h_name, myname); 234*59906Sbostic } else { 235*59906Sbostic printf("time on %s is %d ms. behind time on %s\n", 236*59906Sbostic hp->h_name, -measure_delta, myname); 237*59906Sbostic } 23823785Sgusella } 23923785Sgusella return; 24023785Sgusella } 241*59906Sbostic 242*59906Sbostic 24323785Sgusella /* 24423785Sgusella * finds location of master timedaemon 24523785Sgusella */ 246*59906Sbostic void 247*59906Sbostic msite(argc, argv) 248*59906Sbostic int argc; 249*59906Sbostic char *argv[]; 25023785Sgusella { 25125578Sbloom int cc; 25225578Sbloom fd_set ready; 25323785Sgusella struct sockaddr_in dest; 254*59906Sbostic int i, length; 255*59906Sbostic struct sockaddr from; 25623785Sgusella struct timeval tout; 25723785Sgusella struct tsp msg; 25823785Sgusella struct servent *srvp; 259*59906Sbostic char *tgtname; 26023785Sgusella 261*59906Sbostic if (argc < 1) { 262*59906Sbostic 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 274*59906Sbostic (void)gethostname(myname, sizeof(myname)); 275*59906Sbostic i = 1; 276*59906Sbostic do { 277*59906Sbostic tgtname = (i >= argc) ? myname : argv[i]; 278*59906Sbostic hp = gethostbyname(tgtname); 279*59906Sbostic if (hp == 0) { 280*59906Sbostic fprintf(stderr, "timedc: %s: ", tgtname); 281*59906Sbostic herror(0); 282*59906Sbostic continue; 283*59906Sbostic } 284*59906Sbostic bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); 28523785Sgusella 286*59906Sbostic (void)strcpy(msg.tsp_name, myname); 287*59906Sbostic msg.tsp_type = TSP_MSITE; 288*59906Sbostic msg.tsp_vers = TSPVERSION; 289*59906Sbostic bytenetorder(&msg); 290*59906Sbostic if (sendto(sock, &msg, sizeof(struct tsp), 0, 291*59906Sbostic (struct sockaddr*)&dest, 292*59906Sbostic sizeof(struct sockaddr)) < 0) { 293*59906Sbostic perror("sendto"); 294*59906Sbostic continue; 295*59906Sbostic } 29623785Sgusella 297*59906Sbostic tout.tv_sec = 15; 298*59906Sbostic tout.tv_usec = 0; 299*59906Sbostic FD_ZERO(&ready); 300*59906Sbostic FD_SET(sock, &ready); 301*59906Sbostic if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, 302*59906Sbostic &tout)) { 303*59906Sbostic length = sizeof(struct sockaddr); 304*59906Sbostic cc = recvfrom(sock, &msg, sizeof(struct tsp), 0, 305*59906Sbostic &from, &length); 306*59906Sbostic if (cc < 0) { 307*59906Sbostic perror("recvfrom"); 308*59906Sbostic continue; 309*59906Sbostic } 310*59906Sbostic bytehostorder(&msg); 311*59906Sbostic if (msg.tsp_type == TSP_ACK) { 312*59906Sbostic printf("master timedaemon at %s is %s\n", 313*59906Sbostic tgtname, msg.tsp_name); 314*59906Sbostic } else { 315*59906Sbostic printf("received wrong ack: %s\n", 316*59906Sbostic tsptype[msg.tsp_type]); 317*59906Sbostic } 318*59906Sbostic } else { 319*59906Sbostic printf("communication error with %s\n", tgtname); 32023785Sgusella } 321*59906Sbostic } while (++i < argc); 32223785Sgusella } 32323785Sgusella 32423785Sgusella /* 32523785Sgusella * quits timedc 32623785Sgusella */ 327*59906Sbostic 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 */ 339*59906Sbostic void 34023785Sgusella testing(argc, argv) 341*59906Sbostic int argc; 342*59906Sbostic char *argv[]; 34323785Sgusella { 34423785Sgusella struct servent *srvp; 345*59906Sbostic struct sockaddr_in sin; 34623785Sgusella struct tsp msg; 34723785Sgusella 348*59906Sbostic if (argc < 2) { 349*59906Sbostic 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; 357*59906Sbostic } 35823785Sgusella 35923785Sgusella while (argc > 1) { 36023785Sgusella argc--; argv++; 36123785Sgusella hp = gethostbyname(*argv); 36223785Sgusella if (hp == NULL) { 363*59906Sbostic fprintf(stderr, "timedc: %s: ", *argv); 364*59906Sbostic herror(0); 36523785Sgusella argc--; argv++; 36623785Sgusella continue; 36723785Sgusella } 368*59906Sbostic sin.sin_port = srvp->s_port; 369*59906Sbostic sin.sin_family = hp->h_addrtype; 370*59906Sbostic bcopy(hp->h_addr, &sin.sin_addr.s_addr, hp->h_length); 37123785Sgusella 372*59906Sbostic msg.tsp_type = TSP_TEST; 373*59906Sbostic msg.tsp_vers = TSPVERSION; 374*59906Sbostic (void)gethostname(myname, sizeof(myname)); 375*59906Sbostic (void)strncpy(msg.tsp_name, myname, sizeof(msg.tsp_name)); 376*59906Sbostic bytenetorder(&msg); 377*59906Sbostic if (sendto(sock, &msg, sizeof(struct tsp), 0, 378*59906Sbostic (struct sockaddr*)&sin, 379*59906Sbostic sizeof(struct sockaddr)) < 0) { 38023785Sgusella perror("sendto"); 38123785Sgusella } 38223785Sgusella } 38323785Sgusella } 38423785Sgusella 385*59906Sbostic 38623785Sgusella /* 38723785Sgusella * Enables or disables tracing on local timedaemon 38823785Sgusella */ 389*59906Sbostic void 39023785Sgusella tracing(argc, argv) 391*59906Sbostic int argc; 392*59906Sbostic char *argv[]; 39323785Sgusella { 39423785Sgusella int onflag; 39523785Sgusella int length; 39625578Sbloom int cc; 39725578Sbloom fd_set ready; 39823785Sgusella struct sockaddr_in dest; 399*59906Sbostic 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; 413*59906Sbostic } 41423785Sgusella dest.sin_port = srvp->s_port; 41523785Sgusella dest.sin_family = AF_INET; 41623785Sgusella 417*59906Sbostic (void)gethostname(myname,sizeof(myname)); 418*59906Sbostic 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 429*59906Sbostic (void)strcpy(msg.tsp_name, myname); 43023785Sgusella msg.tsp_vers = TSPVERSION; 43123785Sgusella bytenetorder(&msg); 432*59906Sbostic if (sendto(sock, &msg, sizeof(struct tsp), 0, 433*59906Sbostic (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)) { 443*59906Sbostic length = sizeof(struct sockaddr); 444*59906Sbostic cc = recvfrom(sock, &msg, sizeof(struct tsp), 0, 445*59906Sbostic &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 457*59906Sbostic printf("wrong ack received: %s\n", 45823785Sgusella tsptype[msg.tsp_type]); 45923785Sgusella } else 46023785Sgusella printf("communication error\n"); 46123785Sgusella } 46223785Sgusella 463*59906Sbostic 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); 479*59906Sbostic 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 493*59906Sbostic sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 49423785Sgusella if (sock_raw < 0) { 49523785Sgusella perror("opening raw socket"); 496*59906Sbostic (void) close(sock); 49723785Sgusella return(-1); 49823785Sgusella } 49923785Sgusella return(1); 50023785Sgusella } 501